{"record":{"id":"7e9534148e82dce9","repo":"github/copilot-sdk","slug":"factory-run-and-factory-resume-are-not-allowed-whi","errorCode":null,"errorMessage":"factory.run and factory.resume are not allowed while a factory body is running on this call path.","messagePattern":"factory\\.run and factory\\.resume are not allowed while a factory body is running on this call path\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nodejs/src/session.ts","lineNumber":115,"sourceCode":"    );\n}\n\nfunction copyDefinedFactoryAgentOption<TKey extends keyof FactoryAgentOptions>(\n    source: FactoryAgentOptions,\n    target: FactoryAgentOptions,\n    key: TKey\n): void {\n    const value = source[key];\n    if (value !== undefined) {\n        target[key] = value;\n    }\n}\n\nconst factoryExecutionStore = new AsyncLocalStorage<{ active: boolean }>();\n\nfunction throwIfFactoryExecutionIsActive(): void {\n    if (factoryExecutionStore.getStore()?.active) {\n        throw new Error(\n            \"factory.run and factory.resume are not allowed while a factory body is running on this call path.\"\n        );\n    }\n}\n\n/**\n * Convert a raw hook input received over the wire into its public-facing shape.\n * This deserializes the numeric Unix-ms `timestamp` field on BaseHookInput\n * into a Date and maps the wire `cwd` field to `workingDirectory`.\n */\nfunction deserializeHookInput(raw: unknown): unknown {\n    if (\n        !raw ||\n        typeof raw !== \"object\" ||\n        typeof (raw as { timestamp?: unknown }).timestamp !== \"number\"\n    ) {\n        return raw;\n    }","sourceCodeStart":97,"sourceCodeEnd":133,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/nodejs/src/session.ts#L97-L133","documentation":"The SDK tracks, per async call path via AsyncLocalStorage, whether a factory body (the callback passed to a factory-producing method) is currently executing. Calling factory.run or factory.resume re-entrantly from inside such a body would corrupt execution state, so the library throws this guard error instead.","triggerScenarios":"Calling factory.run() or factory.resume() synchronously (or within an awaited chain on the same async context) inside a factory body — i.e. the run/resume call originates from the callback that is itself being driven by the factory.","commonSituations":"Recursive factory logic, calling run/resume from event handlers registered inside the factory body that execute on the same async context, misusing resume in place of returning a value from the body.","solutions":["Do not call run/resume from within the factory body; return/complete the body first.","Move the nested run/resume call outside the factory callback (e.g. after the awaited result).","If a nested execution is genuinely needed, escape the async context so the guard doesn't see the active store — but prefer restructuring instead.","Register a separate top-level factory rather than reusing the running one recursively."],"exampleFix":"// before\nconst factory = session.factory();\nawait factory.run(async () => {\n  await factory.resume(); // throws: re-entrant\n});\n\n// after\nconst factory = session.factory();\nconst result = await factory.run(async () => {\n  /* body work only */\n});\nawait factory.resume(); // outside the body","handlingStrategy":"try-catch","validationCode":"// don't call run/resume from inside a factory body; restructure the code instead","typeGuard":null,"tryCatchPattern":"try {\n  await factory.run(body);\n} catch (e) {\n  if (e.message.includes('not allowed while a factory body is running')) {\n    // move the nested run/resume outside the body\n  } else throw e;\n}","preventionTips":["Keep factory bodies free of re-entrant run/resume calls.","Resume only after run's promise settles.","Register follow-up work outside the body (after await) rather than inside callbacks sharing the async context."],"tags":["reentrancy","async-local-storage","lifecycle","nodejs"],"backgroundTag":"invalid-state-transition","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"}