Skip to content

fix(async): pooledMap surfaces errors thrown by the input iterable#7169

Open
LeSingh1 wants to merge 2 commits into
denoland:mainfrom
LeSingh1:async-pool-iter-error
Open

fix(async): pooledMap surfaces errors thrown by the input iterable#7169
LeSingh1 wants to merge 2 commits into
denoland:mainfrom
LeSingh1:async-pool-iter-error

Conversation

@LeSingh1
Copy link
Copy Markdown

Fixes #6716.

When an async iterable passed to pooledMap throws (rather than a transformation), the catch block discarded the error and built an AggregateError populated solely from the executing transformations. With no transformation rejections in flight, callers saw only:

AggregateError: Cannot complete the mapping as an error was thrown from an item
    errors: []

The underlying cause was unrecoverable.

Repro from the issue:

import { pooledMap } from "jsr:@std/async/pool";

async function* errorThrowingIterator() {
  throw new Error("Iterator failed on first step!");
  yield 1;
}

const results = pooledMap(2, errorThrowingIterator(), async (i) => i * 2);
for await (const _ of results) {}
// AggregateError, errors: [] — the real cause is lost

After the patch the iterable's error rides through in AggregateError.errors:

message: Cannot complete the mapping as an error was thrown from an item
errors:  [ "Iterator failed on first step!" ]

Implementation: bind the catch's value as iterError and errors.push(iterError) only when it isn't already in errors. The Promise.race rejections from the executing pool are already surfaced via the existing allSettled walk, so the includes check prevents the common transformation-rejection path from duplicating its own reason.

Tests:

  • New pooledMap() surfaces errors thrown by the input iterable (#6716) pins the iterable-throws case.
  • The existing pooledMap() handles errors test (which exercises Promise.race rejections, not iterable throws) still produces exactly two rejections, confirming no double-counting.

All 6 pool_test.ts tests pass.

The catch block in pooledMap's writer loop discarded the error that
came out of `for await (const item of array)` and built an
AggregateError populated solely from the executing transformations.
When the iterable itself threw (and no transformation had rejected),
that meant an empty `AggregateError.errors` — callers saw only the
generic "Cannot complete the mapping" message with no way to recover
the underlying cause (denoland#6716).

Bind the caught value as `iterError` and include it in `errors` if it
isn't already there. Promise.race rejections from the executing pool
are already surfaced via the existing allSettled walk, so the
`includes` check prevents duplicates for the common transformation-
rejection path.

Adds a regression test covering the iterable-throws case and verifies
the existing 'handles errors' test still produces exactly the
expected pair of rejections.

Fixes denoland#6716
@github-actions github-actions Bot added the async label May 30, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 30, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.57%. Comparing base (cdf74a8) to head (d5ee03f).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #7169   +/-   ##
=======================================
  Coverage   94.57%   94.57%           
=======================================
  Files         636      636           
  Lines       52142    52143    +1     
  Branches     9401     9402    +1     
=======================================
+ Hits        49315    49316    +1     
  Misses       2249     2249           
  Partials      578      578           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pooledMap's error message is unhelpful when an error comes from the input async iterable

1 participant