← Debugging Guides

阅读中文版本

Promise.all Rejects on the First Failure — Partial Results Lost

Choose between Promise.all, allSettled, and any by matching the failure policy you want, so one rejection does not discard useful results.

intermediatedebuggingjavascriptpromisesasync

Symptoms

  • Promise.all rejects and the other successful results are unavailable
  • One failing request aborts a whole batch
  • Handling needs per-item success and failure together

Possible causes

  • Promise.all is used when failures should be tolerated per item
  • No catch around individual promises converts rejections
  • The desired semantics were "first success" but all was used

Diagnosis steps

Reproduce the early rejection

node -e "Promise.all([Promise.resolve(1), Promise.reject(new Error('x'))]).catch(e => console.log(e.message))"

Interpretation

all rejects with the first error and the resolved value 1 is not reported.

Switch to allSettled for per-item outcomes

node -e "Promise.allSettled([Promise.resolve(1), Promise.reject(new Error('x'))]).then(r => console.log(r))"

Interpretation

allSettled never rejects and reports each status plus value or reason.

Root cause

Promise.all rejects as soon as any input rejects and discards the remaining results. Promise.allSettled waits for all and reports every outcome; Promise.any resolves on the first success and rejects only if all fail.

Fix

Pick the combinator by intent: all when every result is required, allSettled when partial success is acceptable, any for first-success, and race for first-settled with a timeout.

Risk note

allSettled shifts error handling to you; forgetting to inspect rejected results silently drops failures.

Verify the fix

Run the batch with one failing item and confirm allSettled yields the successful values plus a rejected entry, while all rejects as expected.

Symptoms

The error “Promise.all Rejects on the First Failure — Partial Results Lost” points at a specific failure mode. This guide documents the symptoms you can observe, the commands that isolate the cause, the root cause, the fix, and the checks that prove the fix works.

Observed symptoms include:

  • Promise.all rejects and the other successful results are unavailable
  • One failing request aborts a whole batch
  • Handling needs per-item success and failure together

Reproduce and Diagnose

Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.

Step 1: Reproduce the early rejection

node -e "Promise.all([Promise.resolve(1), Promise.reject(new Error('x'))]).catch(e => console.log(e.message))"

all rejects with the first error and the resolved value 1 is not reported.

Step 2: Switch to allSettled for per-item outcomes

node -e "Promise.allSettled([Promise.resolve(1), Promise.reject(new Error('x'))]).then(r => console.log(r))"

allSettled never rejects and reports each status plus value or reason.

Likely contributors, in order of frequency:

  • Promise.all is used when failures should be tolerated per item
  • No catch around individual promises converts rejections
  • The desired semantics were “first success” but all was used

Root Cause

Promise.all rejects as soon as any input rejects and discards the remaining results. Promise.allSettled waits for all and reports every outcome; Promise.any resolves on the first success and rejects only if all fail.

The Fix

Pick the combinator by intent: all when every result is required, allSettled when partial success is acceptable, any for first-success, and race for first-settled with a timeout.

Watch out: allSettled shifts error handling to you; forgetting to inspect rejected results silently drops failures.

// tolerate partial failures
const results = await Promise.allSettled(urls.map((u) => fetch(u)));
const ok = results.filter((r) => r.status === 'fulfilled').map((r) => r.value);
const failed = results.filter((r) => r.status === 'rejected').map((r) => r.reason);

// all: fail fast when every result is required
const all = await Promise.all(urls.map((u) => fetch(u)));

// any: first success wins
const first = await Promise.any(urls.map((u) => fetch(u)));

Verify and Prevent

Run the batch with one failing item and confirm allSettled yields the successful values plus a rejected entry, while all rejects as expected.

Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.

This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.