github/copilot-sdk · error
parallel() expects an array of functions, not promises…
Error message
parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)
What it means
parallel() requires an array of zero-argument functions (thunks) so it controls when each task starts. Passing an array whose elements are not functions is rejected up front. The message specifically calls out the most common mistake: passing already-started promises instead of thunks.
Solutions
- Pass an array of functions: parallel(() => agent(...), () => agent(...)).
- Ensure the argument is an array, not a single promise or value.
- If work is already started as promises, either keep Promise.all or convert to deferred thunks.
Example fix
// before await session.parallel(agent(taskA), agent(taskB)); // after await session.parallel([() => agent(taskA), () => agent(taskB)]);
Defensive patterns
Strategy: type-guard
Validate before calling
if (!Array.isArray(tasks)) throw new TypeError('parallel() needs an array of thunks'); Type guard
const isThunks = <T>(v: unknown): v is Array<() => T | Promise<T>> => Array.isArray(v) && v.every((x) => typeof x === 'function');
Try / catch
try { await session.parallel(tasks); } catch (e) { if (String(e.message).includes('Wrap each call')) console.error('Pass () => fn(), not fn()'); else throw e; } Prevention
- Always annotate thunk arrays: Array<() => Promise<T>>.
- Never call agent(...) while building the array.
- Enable TypeScript strict mode so promise-vs-function mismatches surface at compile time.
When it happens
Trigger: Calling parallel() with a non-array value (e.g. undefined, a single promise), or with an array of promises/awaited results instead of () => ... wrappers.
Common situations: Migrating from Promise.all style code: tasks.map(task => task.run()) already starts the work and yields promises; accidentally spreading or forgetting the wrapper arrow around agent(...) calls.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Factory limit "timeoutSeconds" must be a positive, finite…
- Invalid auto mode switch request payload
- Invalid exit plan mode request payload
- Invalid hooks invoke payload
- Invalid systemMessage.transform payload
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/91763dea8b755438.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/session.ts:178
);
}
const FACTORY_LOG_FLUSH_DELAY_MS = 10;
const MAX_FACTORY_FANOUT_ITEMS = 4096;
function assertFactoryFanoutSize(kind: "parallel" | "pipeline", size: number): void {
if (size > MAX_FACTORY_FANOUT_ITEMS) {
throw new Error(
`${kind}() accepts at most ${MAX_FACTORY_FANOUT_ITEMS} items; got ${size}.`
);
}
}
async function runFactoryParallel<TResult>(
thunks: Array<() => Promise<TResult> | TResult>
): Promise<Array<TResult | null>> {
if (!Array.isArray(thunks)) {
throw new Error(
"parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
);
}
assertFactoryFanoutSize("parallel", thunks.length);
if (thunks.some((thunk) => typeof thunk !== "function")) {
throw new Error(
"parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)"
);
}
return Promise.all(
thunks.map((thunk) =>
Promise.resolve()
.then(() => thunk())
.catch((error) => {
// Cancellation and hard runtime failures must propagate out
// of the combinator rather than be mapped to a successful
// `null`; otherwise an aborted run, or one that hit a
// resource ceiling or durable-state failure, could beView on GitHub (pinned to cd8cf15dc3)