Workflow AutomationOperationsZapiern8n

Line Items in Automations: The Half-Written Order

An order with multiple line items turns one trigger into N separate writes, and each platform leaves a different half-written shape when write k fails: Zapier runs iterations in parallel so any subset can be missing, n8n finishes each node for every item before starting the next, and Make stops at the failed bundle. The durable fix is a child key derived from the parent ID plus the line's identity, an upsert instead of a create, and a parent status that only flips to complete once the child count matches.

Alexey YushkinFounder, GENERAL INFORMATICS3 min read

An order with six line items is not one record. It is one trigger that becomes six or seven separate writes, and every automation platform handles the moment when write number four fails differently. Zapier runs loop iterations in parallel, so the missing lines can be any subset. n8n finishes each node for every item before the next node starts, so the lines after the failure are missing and none of the later steps ran for anyone. Make processes bundles in order and stops at the one that failed. In all three cases the parent order usually exists and looks complete, and the built-in retry is what turns a half-written order into a duplicated one. The fix is the same on every platform: a child key derived from the parent ID plus the line's identity, an upsert instead of a create, and a parent status that only flips to complete when the child count matches the source.

Line items are a fan-out, and a fan-out stops halfway

Every guide on line items answers the same question: how do I get the array through the tool? Zapier has line item support and the Formatter's line-itemizer, n8n has the Split Out node, Make has the Iterator. That is the mapping half, and it works on the first test order.

The half nobody writes about is what the workflow looks like at 2:14 pm when the target API returns a 429 on the fourth of six child writes. The "create line item" step runs N times, each run is a separate network call, and no transaction wraps them. Three lines exist in the target. Three do not. The parent invoice exists too, because it was written first to get an ID for the children to point at. The customer opens an invoice that is short by half.

This is a different problem from an automation that creates duplicates on a single record. There, the failure is an extra write. Here, the failure is an incomplete set, and the platform's recovery tools are built for single records, not sets.

What a half-written order looks like on each platform

The three platforms fan out in three different ways, and the difference decides what is missing and what a retry does. As of September 2026, this is what the vendor documentation and source code say.

PlatformHow the N child writes runWhat is left after write k of N failsWhat the built-in retry does
Zapier (Looping by Zapier)Every iteration is its own Zap run, and Zapier documents that all iterations execute in parallel rather than one after another. Up to 500 iterations.Any subset of the N lines can be missing, in no particular order, and the surviving lines arrived in arbitrary order too.Autoreplay replays the errored run, which is the single failed iteration, from the failed step. Replay-all-steps on that run re-runs its successful steps. Replaying from the trigger re-runs every iteration.
n8nOne node processes all N items, then the next node processes all N. With the default On Error of Stop Workflow, the node halts at the item that errored.Lines 1 through k-1 exist, lines k through N do not, and no later node ran for any line. Every child is at the same stage.Retry pops the failed node's errored run and re-executes that node from the execution stack, with the input it had, which includes the k-1 items that were already written.
Make (Iterator)Bundles are processed one at a time in order.Bundles 1 through k-1 completed the rest of the flow, bundle k and everything after it did not. Make documents that the failed bundle does not continue and no remaining bundles are processed.With a Break handler and incomplete executions enabled, retry starts at the failed module with the stored bundle. Earlier bundles are not reprocessed.

Two things in that table change how you build. First, on Zapier the lines are unordered. If line position matters, and on an invoice it does, the position has to travel in the payload as a field, because arrival order tells you nothing. Second, the n8n retry is the trap. It does exactly what a person expects, re-run the failed node, and the failed node's input is the whole list. Lines 1 through k-1 get written again. Make's resume is the only one of the three that is safe by default, and only when the failed module's own write did not half-succeed.

Rollback is worse than retry. Make's Rollback handler reverts modules that carry the ACID label, such as MySQL and Data Store, and its documentation is explicit that it cannot undo a Gmail send or a Dropbox delete. A line item created in QuickBooks, HubSpot, or Airtable is on the wrong side of that line. Zapier and n8n have no rollback at all, only the version restore that rolls back the workflow, not the data.

Give every child a key the source already knows

The fix that works on all three platforms is to stop creating children and start upserting them. An upsert needs a key, and the key has to be something the source order already contains, so that a retry, a replay, or a second run of the same trigger computes the same key and lands on the same record.

The key is the parent's ID plus the line's identity within the parent. The second half is where people get it wrong. Three rules from orders we have shipped:

  • Use the source's own line ID when it exists. Shopify line items carry an ID. QuickBooks invoice lines carry an Id within the invoice. Stripe invoice line items have their own object IDs. That ID is stable across retries and across edits to the order.
  • When the source has no line ID, use the position index. A Typeform or Jotform product list, a spreadsheet row with columns like item_1 through item_5, or a pasted purchase order gives you nothing but position. ORD-48213:3 is a fine key for the third line of that order.
  • Never use the SKU alone. One order can carry the same SKU on two lines: two engraved tumblers with different names, two of the same service at different addresses, the same part at two prices because one was a warranty replacement. SKU-only keys collapse those into one line and the customer gets charged for half.

Write the key into a field on the child record that the target lets you search or upsert on. In HubSpot that is a custom property on the line item object. In Airtable it is a text field, and the write step becomes find-then-create-or-update. In Postgres it is a unique constraint and an ON CONFLICT DO UPDATE. The dedup gate is the same idea; the only addition for a fan-out is that the key includes the line, not just the event.

On n8n, pair the key with the node's On Error setting. Set the child-write node to Continue (using error output) so a 429 on line four routes that one item to the error branch while lines five and six still write. The error branch then feeds a retry with the same keys, and the retry cannot duplicate anything. The default Stop Workflow setting is right for most nodes, and wrong for the fan-out write specifically.

Write the parent last, or make it invisible until the children exist

A parent that looks finished while its children are half-written is what makes this failure expensive. The invoice goes out. The pick list prints. The deal amount rolls up from three lines instead of six. The state was visible to humans and to downstream automations before it was true.

If the target lets you write the children first, referencing the parent by an external ID you generate up front, do that and create the parent last. More often the children need the parent's internal ID as a foreign key, so the parent has to exist first. Then give it a status field that starts as pending and treat the flip to complete as the real creation event.

The flip is not "the loop finished." Loops finish with errors inside them. The flip is a count. After the fan-out, count the children in the target that carry this parent's key prefix, compare the count to the number of lines in the source payload, and only then update the parent. If the counts differ, leave the parent pending, and route it to the review queue with the line numbers that are missing. A pending order that a person can see is a Tuesday. A complete order with three lines missing is a refund.

Every downstream automation then triggers on status changed to complete, never on parent created. That one rule stops the pick list from printing early. It also means the fan-out can be retried as often as needed, with the upsert absorbing repeats, and nothing downstream moves until the set is whole. It is the same shape as the claim-before-work pattern in overlapping runs: the record's own status is the lock, not the platform's run state.

When you can skip the loop entirely

The best fan-out is the one that does not happen. Before you build the loop, check whether the target will take the lines inside the parent's payload.

QuickBooks Online accepts an invoice with its Line array in one request. Shopify accepts an order with its line_items array. Stripe builds an invoice from line items you attach before finalizing, so the customer never sees a partial one. In each of those, a network failure means the whole thing did not write, which is a state you can retry without thinking. Half-written is impossible by construction.

Salesforce goes the furthest. The composite sObject Tree resource creates a parent record and its nested children, up to 200 records across the request and five levels deep, in one call, and the documentation states that if an error occurs while creating a record, the entire request fails. That is an atomic order-plus-lines write into a CRM, which no loop on any platform can give you. On Zapier or Make it is a single Webhooks or HTTP step with a JSON body; on n8n it is an Aggregate node that folds the lines into one item, followed by a single HTTP Request node.

The loop is for targets that model lines as their own objects. HubSpot line items are separate CRM records attached to a deal by association. Airtable linked records are separate rows. A database without a transaction wrapper is separate inserts. Those are the cases where the key, the upsert, and the status flip earn their cost. A target that offers both should get the nested write every time, even if the per-line connector is the one with the friendly dropdown.

Where to start

Pull up the last month of orders in whichever system receives the lines and run one query: parents whose child count does not match the source. Most operators who do this find a handful, all silently short, all invoiced. That list is the argument for the rebuild and the backlog to fix by hand this week.

Then rebuild the fan-out in this order: child key from parent ID plus line identity, upsert instead of create, parent status pending until the count matches, downstream triggers moved to the status flip. On n8n, switch the child-write node to Continue (using error output). On Zapier, put the line position in the payload and stop trusting arrival order. And if the target accepts the lines in the parent's payload, delete the loop and send one request.

This is the design that separates an order pipeline that survives a bad afternoon from one that quietly ships short invoices, and it is standard in the workflow automation systems we build for operations moving orders between a storefront, a CRM, and an accounting system. If you are not sure whether your build writes the parent first or last, or what its retry actually re-sends, tell us what the order flow looks like and we will map it.

Frequently Asked Questions

SOURCES & CITATIONS

  1. Understanding Looping by Zapier Zapierhttps://help.zapier.com/hc/en-us/articles/42969233918477-Understanding-Looping-by-Zapier
  2. Rollback error handler Makehttps://help.make.com/rollback-error-handler
  3. sObject Tree, REST API Developer Guide Salesforcehttps://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/resources_composite_sobject_tree.htm
  4. execution.service.ts, retry method (n8n source) n8n (GitHub)https://github.com/n8n-io/n8n/blob/master/packages/cli/src/executions/execution.service.ts

About Alexey Yushkin

Alexey is the founder of GENERAL INFORMATICS LLC. He designs and ships AI and automation systems for businesses and operators across the US.

Connect on LinkedIn

Related reading

Want this kind of system in your business?

We build practical AI and automation systems for operators. Send us your current workflow and we will show you what to automate first.