Tips > Reliability & Performance

Handle Partial Failures in Batch Operations

When processing batches (importing records, sending emails, updating a CRM), some items will succeed and others will fail.

TipAdvanced2 min read

When processing batches (importing records, sending emails, updating a CRM), some items will succeed and others will fail. Track both counts, handle them separately, and produce a clear execution summary. This prevents the all-or-nothing problem where one bad record kills the entire batch.

Real-world example: A nightly workflow imports 500 contacts from a CSV into HubSpot. 12 contacts have invalid email addresses and fail. The other 488 should still be imported, and the 12 failures should be reported.

// Code node: "Process Batch Results"
// Place after a node with "Continue on Fail" enabled

const allItems = $input.all();

const results = {
  total: allItems.length,
  succeeded: 0,
  failed: 0,
  successItems: [],
  failedItems: []
};

for (const item of allItems) {
  if (item.json.error) {
    results.failed++;
    results.failedItems.push({
      originalData: item.json,
      error: item.json.error.message || 'Unknown error',
      index: results.succeeded + results.failed - 1
    });
  } else {
    results.succeeded++;
    results.successItems.push(item.json);
  }
}

results.successRate = Math.round(
  (results.succeeded / results.total) * 100
);

return [{
  json: results
}];
```text
Generate a batch processing report:

```javascript
// Code node: "Generate Batch Report"
const r = $input.first().json;

const report = {
  summary: `Batch complete: ${r.succeeded}/${r.total} succeeded (${r.successRate}%)`,
  succeeded: r.succeeded,
  failed: r.failed,
  total: r.total,
  successRate: r.successRate,
  needsAttention: r.failed > 0,
  failedItemsSample: r.failedItems.slice(0, 10).map(f => ({
    error: f.error,
    data: JSON.stringify(f.originalData).substring(0, 200)
  }))
};

// Determine if this batch needs an alert
if (r.successRate < 90) {
  report.alertLevel = 'critical';
  report.alertMessage = `Batch success rate below 90%: only ${r.successRate}%`;
} else if (r.failed > 0) {
  report.alertLevel = 'warning';
  report.alertMessage = `${r.failed} items failed in batch`;
} else {
  report.alertLevel = 'info';
  report.alertMessage = 'All items processed successfully';
}

return [{ json: report }];
```text
```yaml
Routing after the report:

[Batch Report] --> [Switch: alertLevel]
                      |
           +----------+----------+
           |          |          |
       [critical]  [warning]  [info]
           |          |          |
       [Slack +    [Slack    [Log to
        DLQ for     alert]    DB only]
        failed
        items]
```text
This gives you full visibility into batch health. A 95% success rate might be acceptable; a 50% success rate triggers immediate investigation.

**Related:** [Use "Pin Data" to Freeze Node Output](../testing-and-debugging/01-use-pin-data-to-freeze-node-output.md) | [Break Large Workflows into Sub-Workflows](../workflow-architecture/01-break-large-workflows-into-sub-workflows.md)

Want this running in your stack?

I build production n8n and Cloudflare automation for teams — the same engineering behind HarperFlow. Fixed-price, escrow-protected, US-based.