github/copilot-sdk · error
Duplicate factory name
Error message
Duplicate factory name "${definition.meta.name}". Factory names must be unique within a joinSession call. What it means
During joinSession, each factory handle is resolved to a definition and stored in this.factories keyed by meta.name. Registering two factories with the same name within one joinSession call is ambiguous (which definition should serve the name?), so it throws before mutating further.
Solutions
- Give each factory a unique meta.name before joining.
- Deduplicate the factories array before passing it to joinSession.
- If two entries are truly the same factory, remove one from the list.
Example fix
// before
joinSession({ factories: [loggerFactory, loggerFactory] });
// after
joinSession({ factories: [...new Map(defs.map((d) => [getFactoryDefinition(d).meta.name, d])).values()] }); Defensive patterns
Strategy: validation
Validate before calling
const names = factories.map((f) => getFactoryDefinition(f).meta.name);
const dupes = names.filter((n, i) => names.indexOf(n) !== i);
if (dupes.length) throw new Error(`Duplicate factory names: ${dupes.join(', ')}`); Try / catch
try { await joinSession({ factories }); } catch (e) { if (String(e.message).includes('Duplicate factory name')) console.error('Deduplicate factories by meta.name before joining'); else throw e; } Prevention
- Deduplicate factories by meta.name before every joinSession call.
- When forking a factory definition, change meta.name too.
- Avoid spreading the same factories array twice into the config.
When it happens
Trigger: Passing a factories array to joinSession containing two handles whose definitions share the same meta.name — duplicates from spreading lists, or a factory accidentally included twice.
Common situations: Combining [ ...baseFactories, ...baseFactories ] or shared defaults arrays; copying a factory and changing only its behavior, not meta.name; re-exporting the same definition under two variable names.
Related errors
- Factory phase title " " is declared more than once
- 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
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/3f555edde0644dff.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/session.ts:1447
}
/**
* Registers factory closures and reverse-RPC handlers for this session.
*
* @param factories - Factory handles declared by the joining extension.
* @internal Called by the SDK when an extension joins a session.
*/
registerFactories(factories?: FactoryHandle[]): void {
this.factories.clear();
if (!factories || factories.length === 0) {
delete this.clientSessionApis.factory;
return;
}
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,
});
}
View on GitHub (pinned to cd8cf15dc3)