github/copilot-sdk · error

factory.run and factory.resume are not allowed while a…

Error message

factory.run and factory.resume are not allowed while a factory body is running on this call path.

What it means

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.

Solutions

  1. Do not call run/resume from within the factory body; return/complete the body first.
  2. Move the nested run/resume call outside the factory callback (e.g. after the awaited result).
  3. If a nested execution is genuinely needed, escape the async context so the guard doesn't see the active store — but prefer restructuring instead.
  4. Register a separate top-level factory rather than reusing the running one recursively.

Example fix

// before
const factory = session.factory();
await factory.run(async () => {
  await factory.resume(); // throws: re-entrant
});

// after
const factory = session.factory();
const result = await factory.run(async () => {
  /* body work only */
});
await factory.resume(); // outside the body
Defensive patterns

Strategy: try-catch

Validate before calling

// don't call run/resume from inside a factory body; restructure the code instead

Try / catch

try {
  await factory.run(body);
} catch (e) {
  if (e.message.includes('not allowed while a factory body is running')) {
    // move the nested run/resume outside the body
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/7e9534148e82dce9. Report an issue: GitHub.

Appendix: source

Thrown at nodejs/src/session.ts:115

    );
}

function copyDefinedFactoryAgentOption<TKey extends keyof FactoryAgentOptions>(
    source: FactoryAgentOptions,
    target: FactoryAgentOptions,
    key: TKey
): void {
    const value = source[key];
    if (value !== undefined) {
        target[key] = value;
    }
}

const factoryExecutionStore = new AsyncLocalStorage<{ active: boolean }>();

function throwIfFactoryExecutionIsActive(): void {
    if (factoryExecutionStore.getStore()?.active) {
        throw new Error(
            "factory.run and factory.resume are not allowed while a factory body is running on this call path."
        );
    }
}

/**
 * Convert a raw hook input received over the wire into its public-facing shape.
 * This deserializes the numeric Unix-ms `timestamp` field on BaseHookInput
 * into a Date and maps the wire `cwd` field to `workingDirectory`.
 */
function deserializeHookInput(raw: unknown): unknown {
    if (
        !raw ||
        typeof raw !== "object" ||
        typeof (raw as { timestamp?: unknown }).timestamp !== "number"
    ) {
        return raw;
    }

View on GitHub (pinned to cd8cf15dc3)