github/copilot-sdk · error
Factory phase titles must not be empty
Error message
Factory phase titles must not be empty
What it means
validatePhases rejects factory phase definitions whose title is empty or consists only of whitespace. Phase titles identify stages of a factory and are used for display and uniqueness checks, so an empty title is considered invalid metadata and fails at defineFactory time.
Solutions
- Give every phase a non-empty title string with at least one non-whitespace character.
- Validate titles before calling defineFactory, especially when they come from data files or user input.
- Fix the data source (translation table, JSON, spreadsheet) that is producing empty titles.
- Trim and check user-supplied titles at input boundaries.
Example fix
// before
defineFactory({ name: 'build', phases: [{ title: ' ', steps: [] }] });
// after
defineFactory({ name: 'build', phases: [{ title: 'Compile', steps: [] }] }); Defensive patterns
Strategy: validation
Validate before calling
for (const p of phases) {
if (typeof p.title !== 'string' || p.title.trim().length === 0) throw new TypeError(`Phase title must be non-empty (got ${JSON.stringify(p.title)})`);
} Type guard
function hasTitle(p) { return typeof p.title === 'string' && p.title.trim().length > 0; } Try / catch
try {
defineFactory(meta);
} catch (e) {
if (e.message === 'Factory phase titles must not be empty') console.error('A phase is missing a title');
throw e;
} Prevention
- Validate phase data at load time (i18n keys, spreadsheets, JSON)
- Use zod/ajv schemas requiring non-empty strings for titles
- Trim user-supplied titles at input boundaries
- Never leave placeholder empty titles during scaffolding
When it happens
Trigger: Calling defineFactory with a phase whose title is '' or contains only spaces/newlines (title.trim().length === 0). Also occurs when titles are derived from data (e.g. a missing i18n string or a field that failed to map) and end up as empty strings.
Common situations: Localization files missing a translation key resulting in ''; spreadsheet/JSON-driven phase generation with blank rows; refactoring that removed a default title; accidental whitespace-only strings from user input.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
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…
- sessionFs.initialCwd is required
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/d41848b79843b83c.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/factory.ts:468
const maxNanoAiu = Math.round(limits.maxAiCredits * NANO_AIU_PER_AIU);
if (
!Number.isFinite(limits.maxAiCredits) ||
limits.maxAiCredits <= 0 ||
!Number.isSafeInteger(maxNanoAiu) ||
maxNanoAiu < 1
) {
throw new Error(
'Factory limit "maxAiCredits" must be a positive, finite number that rounds to a safe positive integer nano-AIU ceiling'
);
}
}
}
function validatePhases(meta: FactoryMeta): void {
const titles = new Set<string>();
for (const phase of meta.phases) {
if (phase.title.trim().length === 0) {
throw new Error("Factory phase titles must not be empty");
}
if (titles.has(phase.title)) {
throw new Error(`Factory phase title "${phase.title}" is declared more than once`);
}
titles.add(phase.title);
}
}
/**
* Defines an extension-authored factory and returns an opaque registration handle.
*
* @experimental Part of the experimental Agent Factories surface and may
* change or be removed in future SDK or CLI releases.
*/
export function defineFactory<
TArgs extends JsonValue = JsonValue,
TResult extends JsonValue | void = JsonValue | void,
>(definition: FactoryDefinition<TArgs, TResult>): FactoryHandle<TArgs, TResult> {View on GitHub (pinned to cd8cf15dc3)