github/copilot-sdk · error · ResponseError

factory_not_found

factory_not_found

Error message

No factory registered with name "${params.name}"

What it means

Thrown by CopilotSession when the client invokes the `factory.execute` session API with a `name` that has no corresponding factory registered via the session's factory registry (a Map lookup misses). The SDK throws a ResponseError with ErrorCodes.InvalidParams and a machine-readable `code: "factory_not_found"`. It prevents silently executing an undefined workflow.

Solutions

  1. List the registered factory names and confirm the exact key (case-sensitive) before executing
  2. Register the factory with the exact name being requested via the session's factory registration API
  3. Fix the name passed to factory.execute so it matches the registration
  4. Ensure registration happens on the same session instance and before any execute call

Example fix

// before
await session.factory.execute({ name: "deploy-app" });
// after
session.registerFactory("deploy-app", { run: async (ctx) => { /* ... */ } });
await session.factory.execute({ name: "deploy-app" });
Defensive patterns

Strategy: validation

Validate before calling

const names = session.listFactories?.() ?? [];
if (!names.includes(params.name)) throw new Error(`Unknown factory: ${params.name}`);

Type guard

function hasFactory(session, name) {
  return typeof session.listFactories === "function" && session.listFactories().includes(name);
}

Try / catch

try {
  await session.factory.execute({ name });
} catch (err) {
  if (err?.code === "factory_not_found") {
    console.error(`Factory "${err.data?.name}" is not registered; check registration order/naming.`);
  } else throw err;
}

Prevention

When it happens

Trigger: Calling session factory execute API with a factory name that was never registered, or registered under a different name; a typo in the factory name; executing a factory after the registration code path never ran.

Common situations: Typos or casing mismatches between registerFactory and execute calls; registration code skipped because of conditional init; factories registered on a different CopilotSession instance than the one executing.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at nodejs/src/session.ts:1460

        }

        for (const handle of factories) {
            const definition = getFactoryDefinition(handle);
            if (this.factories.has(definition.meta.name)) {
                throw new Error(
                    `Duplicate factory name "${definition.meta.name}". Factory names must be unique within a joinSession call.`
                );
            }
            this.factories.set(definition.meta.name, definition);
        }

        const self = this;
        this.clientSessionApis.factory = {
            async execute(params) {
                const definition = self.factories.get(params.name);
                if (!definition) {
                    const message = `No factory registered with name "${params.name}"`;
                    throw new ResponseError(ErrorCodes.InvalidParams, message, {
                        code: "factory_not_found",
                        name: params.name,
                    });
                }

                const controller = new AbortController();
                // Keyed by execution token as well as run ID so overlapping
                // attempts for one run stay individually addressable.
                let controllersForRun = self.factoryAbortControllers.get(params.runId);
                if (controllersForRun === undefined) {
                    controllersForRun = new Map();
                    self.factoryAbortControllers.set(params.runId, controllersForRun);
                }
                controllersForRun.set(params.executionToken, controller);
                const progress = new FactoryProgressBuffer(async (lines) => {
                    await self.rpc.factory.log({
                        runId: params.runId,
                        executionToken: params.executionToken,

View on GitHub (pinned to cd8cf15dc3)