Yeachan-Heo/oh-my-codex · error · Error
catalog_manifest_invalid:agents[${index}].canonical
Error message
catalog_manifest_invalid:agents[${index}].canonical What it means
Agent entries with status alias or merged must specify a canonical target agent name; this error fires when canonical is missing or whitespace-only on such an entry. It mirrors the skills canonical requirement.
Source
Thrown at src/catalog/schema.ts:114
assertNonEmptyString(entry.status, `agents[${index}].status`);
if (!AGENT_CATEGORIES.has(entry.category as CatalogAgentCategory)) {
throw new Error(`catalog_manifest_invalid:agents[${index}].category`);
}
if (!ENTRY_STATUSES.has(entry.status as CatalogEntryStatus)) {
throw new Error(`catalog_manifest_invalid:agents[${index}].status`);
}
const name = entry.name.trim();
if (seenAgents.has(name)) throw new Error(`catalog_manifest_invalid:duplicate_agent:${name}`);
seenAgents.add(name);
const canonical = typeof entry.canonical === 'string' && entry.canonical.trim() !== ''
? entry.canonical.trim()
: undefined;
if ((entry.status === 'alias' || entry.status === 'merged') && !canonical) {
throw new Error(`catalog_manifest_invalid:agents[${index}].canonical`);
}
return {
name,
category: entry.category as CatalogAgentCategory,
status: entry.status as CatalogEntryStatus,
canonical,
};
});
for (const coreSkill of REQUIRED_CORE_SKILLS) {
const skill = skills.find((s) => s.name === coreSkill);
if (!skill || skill.status !== 'active') {
throw new Error(`catalog_manifest_invalid:missing_core_skill:${coreSkill}`);
}
}
return {View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Add "canonical": "<primary agent name>" to the entry
- Verify the canonical value names an existing agent entry
- Change status back to active if the agent is not an alias
Example fix
// before
{ "name": "rev", "category": "review", "status": "alias" }
// after
{ "name": "rev", "category": "review", "status": "alias", "canonical": "reviewer" } Defensive patterns
Strategy: validation
Validate before calling
for (const a of raw.agents) {
if ((a.status === 'alias' || a.status === 'merged') && !(typeof a.canonical === 'string' && a.canonical.trim())) {
/* add canonical or change status */
}
} Type guard
const hasCanonicalIfNeeded = (a: Record<string, unknown>) => !(a.status === 'alias' || a.status === 'merged') || (typeof a.canonical === 'string' && a.canonical.trim() !== '');
Prevention
- Add canonical whenever an agent becomes an alias
- Validate the manifest after renames
When it happens
Trigger: An agents[i] entry with "status": "alias" or "merged" but no canonical field.
Common situations: Converting an agent to an alias during a rename without adding canonical, or generators dropping canonical fields.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- catalog_manifest_invalid:skills[${index}].canonical
- catalog_manifest_invalid:agents[${index}]
- catalog_manifest_invalid:agents[${index}].category
- catalog_manifest_invalid:agents[${index}].status
- catalog_manifest_invalid:duplicate_agent:${name}
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/9d528149d38b7373.
Report an issue: GitHub.