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

catalog_manifest_missing

Error message

catalog_manifest_missing

What it means

readCatalogManifest locates the catalog manifest by probing templates/catalog-manifest.json, src/catalog/manifest.json, and dist/catalog/manifest.json under the package root; if none exists it throws catalog_manifest_missing. This protects callers from silently operating without a catalog.

Source

Thrown at src/catalog/reader.ts:26

  ['src', 'catalog', 'manifest.json'],
  ['dist', 'catalog', 'manifest.json'],
] as const;

let cachedManifest: CatalogManifest | null = null;
let cachedPath: string | null = null;

function resolveManifestPath(packageRoot: string): string | null {
  for (const segments of MANIFEST_CANDIDATE_PATHS) {
    const fullPath = join(packageRoot, ...segments);
    if (existsSync(fullPath)) return fullPath;
  }
  return null;
}

export function readCatalogManifest(packageRoot: string = getPackageRoot()): CatalogManifest {
  const path = resolveManifestPath(packageRoot);
  if (!path) {
    throw new Error('catalog_manifest_missing');
  }

  if (cachedManifest && cachedPath === path) return cachedManifest;

  const raw = JSON.parse(readFileSync(path, 'utf8')) as unknown;
  const manifest = validateCatalogManifest(raw);
  cachedManifest = manifest;
  cachedPath = path;
  return manifest;
}

export function tryReadCatalogManifest(packageRoot: string = getPackageRoot()): CatalogManifest | null {
  try {
    return readCatalogManifest(packageRoot);
  } catch {
    return null;
  }
}

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Verify which path exists: templates/catalog-manifest.json or src/catalog/manifest.json or dist/catalog/manifest.json under the root you pass
  2. If dist is incomplete, rebuild the package so dist/catalog/manifest.json is emitted
  3. If you pass packageRoot explicitly, point it at the actual package root containing the manifest
  4. Use tryReadCatalogManifest() if a null return is acceptable in your flow

Example fix

// before
const manifest = readCatalogManifest(someDir); // throws

// after
import { tryReadCatalogManifest } from './catalog/reader.js';
const manifest = tryReadCatalogManifest(someDir) ?? fallbackManifest;
Defensive patterns

Strategy: fallback

Validate before calling

import { tryReadCatalogManifest } from './catalog/reader.js';
const manifest = tryReadCatalogManifest(root);
if (!manifest) { /* use fallback catalog or fail gracefully */ }

Try / catch

try { readCatalogManifest(root); } catch (e) { if ((e as Error).message === 'catalog_manifest_missing') { /* fallback */ } throw e; }

Prevention

When it happens

Trigger: Calling readCatalogManifest(packageRoot) (directly or via getCatalogCounts, contract, installableAgentNames) when the package root has none of the three candidate manifest files — typical for an incompletely built package or a wrong packageRoot argument.

Common situations: Running from a checkout before generating the manifest, a dist/ build that pruned catalog files, passing a custom packageRoot that doesn't contain the manifest, or packaging rules excluding JSON files.

Related errors


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