Yeachan-Heo/oh-my-codex · error · Error

catalog_manifest_invalid:skills

Error message

catalog_manifest_invalid:skills

What it means

validateCatalogManifest requires the 'skills' key to be an array of skill entries. This error means 'skills' is missing, an object, or a scalar. Note that an empty array passes this check; per-entry problems surface as skills[i] errors.

Source

Thrown at src/catalog/schema.ts:52

  return typeof value === 'object' && value !== null && !Array.isArray(value);
}

function assertNonEmptyString(value: unknown, field: string): asserts value is string {
  if (typeof value !== 'string' || value.trim() === '') {
    throw new Error(`catalog_manifest_invalid:${field}`);
  }
}

export function validateCatalogManifest(input: unknown): CatalogManifest {
  if (!isObject(input)) throw new Error('catalog_manifest_invalid:root');

  if (typeof input.schemaVersion !== 'number' || !Number.isInteger(input.schemaVersion)) {
    throw new Error('catalog_manifest_invalid:schemaVersion');
  }

  assertNonEmptyString(input.catalogVersion, 'catalogVersion');

  if (!Array.isArray(input.skills)) throw new Error('catalog_manifest_invalid:skills');
  if (!Array.isArray(input.agents)) throw new Error('catalog_manifest_invalid:agents');

  const seenSkills = new Set<string>();
  const skills: CatalogSkillEntry[] = input.skills.map((entry, index) => {
    if (!isObject(entry)) throw new Error(`catalog_manifest_invalid:skills[${index}]`);
    assertNonEmptyString(entry.name, `skills[${index}].name`);
    assertNonEmptyString(entry.category, `skills[${index}].category`);
    assertNonEmptyString(entry.status, `skills[${index}].status`);

    if (!SKILL_CATEGORIES.has(entry.category as CatalogSkillCategory)) {
      throw new Error(`catalog_manifest_invalid:skills[${index}].category`);
    }
    if (!ENTRY_STATUSES.has(entry.status as CatalogEntryStatus)) {
      throw new Error(`catalog_manifest_invalid:skills[${index}].status`);
    }

    const name = entry.name.trim();
    if (seenSkills.has(name)) throw new Error(`catalog_manifest_invalid:duplicate_skill:${name}`);

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Change skills to an array of entry objects (use [] if there are none)
  2. Regenerate the manifest from canonical source data
  3. Add validateCatalogManifest to CI to catch regressions

Example fix

// before
"skills": { "autopilot": { "category": "execution" } }

// after
"skills": [ { "name": "autopilot", "category": "execution", "status": "active" } ]
Defensive patterns

Strategy: validation

Validate before calling

if (!Array.isArray(raw.skills)) { /* reject or coerce to array before validation */ }

Type guard

function hasSkillsArray(v: unknown): v is { skills: unknown[] } { return typeof v === 'object' && v !== null && Array.isArray((v as any).skills); }

Prevention

When it happens

Trigger: A manifest JSON where "skills" is absent, {}, or a string; e.g. someone keyed skills by name instead of listing them.

Common situations: Restructuring the manifest into a map for convenience, or generators that omit skills entirely in agent-only catalogs without emitting [].

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/b326c481c70380ee. Report an issue: GitHub.