{"record":{"id":"6179b99c8ac3d616","repo":"github/copilot-sdk","slug":"kind-accepts-at-most-max-factory-fanout-ite","errorCode":null,"errorMessage":"${kind}() accepts at most ${MAX_FACTORY_FANOUT_ITEMS} items; got ${size}.","messagePattern":"(.+?)\\(\\) accepts at most (.+?) items; got (.+?)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nodejs/src/session.ts","lineNumber":168,"sourceCode":"        return false;\n    }\n    const instance = value as Partial<OpenCanvasInstance>;\n    return (\n        typeof instance.instanceId === \"string\" &&\n        instance.instanceId.length > 0 &&\n        typeof instance.extensionId === \"string\" &&\n        instance.extensionId.length > 0 &&\n        typeof instance.canvasId === \"string\" &&\n        instance.canvasId.length > 0\n    );\n}\n\nconst FACTORY_LOG_FLUSH_DELAY_MS = 10;\nconst MAX_FACTORY_FANOUT_ITEMS = 4096;\n\nfunction assertFactoryFanoutSize(kind: \"parallel\" | \"pipeline\", size: number): void {\n    if (size > MAX_FACTORY_FANOUT_ITEMS) {\n        throw new Error(\n            `${kind}() accepts at most ${MAX_FACTORY_FANOUT_ITEMS} items; got ${size}.`\n        );\n    }\n}\n\nasync function runFactoryParallel<TResult>(\n    thunks: Array<() => Promise<TResult> | TResult>\n): Promise<Array<TResult | null>> {\n    if (!Array.isArray(thunks)) {\n        throw new Error(\n            \"parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)\"\n        );\n    }\n    assertFactoryFanoutSize(\"parallel\", thunks.length);\n    if (thunks.some((thunk) => typeof thunk !== \"function\")) {\n        throw new Error(\n            \"parallel() expects an array of functions, not promises. Wrap each call: () => agent(...)\"\n        );","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/nodejs/src/session.ts#L150-L186","documentation":"session.parallel() and session.pipeline() cap the number of concurrently fanned-out items at MAX_FACTORY_FANOUT_ITEMS (4096). assertFactoryFanoutSize is called by runFactoryParallel and runFactoryPipeline to reject oversized inputs before scheduling, protecting the session from unbounded promise allocation. It is a hard guardrail, not a transient condition.","triggerScenarios":"Calling parallel(thunks) or pipeline(items, ...stages) with more than 4096 elements in the input array.","commonSituations":"Batching thousands of agent/tool invocations built from a large dataset (e.g. per-file or per-row work over a big directory or DB export) without chunking; loop-generated task arrays that grew with the codebase.","solutions":["Split the input into chunks of at most 4096 and call parallel()/pipeline() per chunk, awaiting each batch.","Reduce fan-out by grouping related work into fewer thunks (e.g. process batches of items inside one thunk).","Queue overflow items and run them as earlier thunks complete."],"exampleFix":"// before\nconst results = await session.parallel(files.map((f) => () => agent(f)));\n// after\nfor (let i = 0; i < files.length; i += 4096) {\n  const batch = files.slice(i, i + 4096).map((f) => () => agent(f));\n  results.push(...(await session.parallel(batch)));\n}","handlingStrategy":"validation","validationCode":"if (items.length > 4096) throw new Error(`Fan-out too large: ${items.length}; chunk into batches of <= 4096`);","typeGuard":null,"tryCatchPattern":"try { await session.parallel(thunks); } catch (e) { if (String(e.message).includes('accepts at most')) chunkAndRetry(thunks); else throw e; }","preventionTips":["Chunk any dynamically sized task list before fanning out.","Centralize a runBatched() helper that enforces the 4096 limit.","Add an upper-bound unit test for generated task arrays."],"tags":["limit-exceeded","concurrency","fanout"],"backgroundTag":"value-out-of-range","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}