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
- List the registered factory names and confirm the exact key (case-sensitive) before executing
- Register the factory with the exact name being requested via the session's factory registration API
- Fix the name passed to factory.execute so it matches the registration
- 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
- Keep factory names in a shared constants module used by both registration and execution
- Log registered factory names at session startup
- Register all factories immediately after session construction, before any execute call
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
- Factory limit "timeoutSeconds" must be a positive, finite…
- Factory limit "timeoutSeconds" must not exceed
- Factory limit "maxAiCredits" must be a positive, finite…
- Factory phase titles must not be empty
- Factory phase title " " is declared more than once
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)