Hmbown/CodeWhale · error · Error
parallel(): max items per call
Error message
parallel(): max ${MAX_ITEMS} items per call What it means
Thrown by the prelude's `globalThis.parallel` in vm.rs when the thunks array exceeds MAX_ITEMS (the PARALLEL_MAX_ITEMS constant baked into the prelude template). The cap bounds fan-out size so replayed runs stay within predictable resource limits.
Solutions
- Chunk the work: split items into batches of at most MAX_ITEMS and run batches sequentially (or via pipeline).
- Batch inside the host task instead: send the whole collection to one `task()` call and let the host process it.
- Raise PARALLEL_MAX_ITEMS if your workload legitimately needs more (rebuild with a larger constant).
- Pre-check `thunks.length` in-script and fail with a clearer domain-specific message.
Example fix
// before
const results = await parallel(items.map(makeThunk));
// after
const results = [];
for (let i = 0; i < items.length; i += MAX) {
results.push(...await parallel(items.slice(i, i + MAX).map(makeThunk)));
} Defensive patterns
Strategy: validation
Validate before calling
function assertFanoutSize(thunks, MAX_ITEMS) {
if (thunks.length > MAX_ITEMS) {
throw new Error(`fan-out of ${thunks.length} exceeds parallel() cap of ${MAX_ITEMS}; chunk the input`);
}
} Try / catch
try {
const results = await parallel(thunks);
} catch (e) {
if (e.message.startsWith('parallel(): max ')) {
const max = Number(e.message.match(/max (\d+)/)?.[1]);
console.error(`chunk input into batches of ${max} or move bulk work into a single host task`);
} else throw e;
} Prevention
- Chunk large collections into batches within MAX_ITEMS.
- Prefer one host task over per-item thunks for bulk data.
- Cap fan-out at the source (paginate/limit inputs).
- Read the cap from the error message rather than guessing the constant.
When it happens
Trigger: Calling `parallel(thunks)` where `thunks.length > MAX_ITEMS` (the limit value is printed in the error message); building the array dynamically from a large input collection without chunking.
Common situations: Mapping a large dataset (thousands of rows) into per-item thunks; unbounded fan-out over user-supplied lists; a config change that grew batch sizes past the cap.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- parallel(): max " + MAX_ITEMS + " items per call
- continual harness is full
- continual harness state
- fn + "(): unknown mode " + JSON.stringify(opts.mode) + "…
- (): unknown mode ; expected one of
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/fc8f7236ed5a16da.
Report an issue: GitHub.
Appendix: source
Thrown at crates/workflow-js/src/vm.rs:1546
const envelope = JSON.parse(await hostTask(JSON.stringify(opts)));
if (envelope.error !== undefined) {
const err = new Error(envelope.error);
// The host always names the kind; a missing one means an envelope this
// prelude did not produce, which is not a typed task failure.
err.kind = HOST_KINDS.indexOf(envelope.error_kind) !== -1
? envelope.error_kind
: SCRIPT_KIND;
throw err;
}
return envelope.value;
};
globalThis.parallel = (thunks, opts) => {
if (!Array.isArray(thunks)) {
throw new TypeError("parallel(): expected an array of thunks");
}
if (thunks.length > MAX_ITEMS) {
throw new Error("parallel(): max " + MAX_ITEMS + " items per call");
}
const mode = slotMode("parallel", opts);
const failFast = mode === "fail-fast";
const partial = mode === "partial";
const errors = [];
// Returns the slot value, or throws to reject the whole fan-out.
const onSlotError = (index, err) => {
const kind = taskErrorKind(err);
const message = taskErrorText(err);
stampKind(err, kind);
// Cancellation is the run's deadline in every mode, partial included.
if (kind === "cancelled") throw err;
if (partial) {
// Opt-in partial mode: every non-cancellation slot failure becomes a
// structured value the script can branch on. It never masquerades as
// a success -- `__taskError` is the whole point of the shape.
errors.push({ index: index, kind: kind, message: message });
hostLog(View on GitHub (pinned to 73e0f67d83)