vercel-labs/agent-skills · error · Error

codebase.json must be scan-codebase output with stack, route

Error message

codebase.json must be scan-codebase output with stack, routes[], and findings[].

What it means

Thrown by mergeSignals() when the second `codebase` argument is not valid scan-codebase output — it must be an object with `routes` (array), `findings` (array), and a truthy `stack`. Any of these missing/falsy means the file is not from scan-codebase, and annotating it against signals would produce a malformed merged brief.

Source

Thrown at skills/vercel-optimize/scripts/merge-signals.mjs:45

  const merged = mergeSignals(signals, codebase);
  const body = JSON.stringify(merged, null, 2) + '\n';
  if (args.outPath) {
    await writeOutput(args.outPath, body, { force: args.force });
    log(`wrote ${args.outPath}`);
  } else {
    process.stdout.write(body);
  }
}

export function mergeSignals(signals, codebase) {
  assertObject(signals, 'signals');
  assertObject(codebase, 'codebase scan');

  if (!signals.schemaVersion) {
    throw new Error('signals.json is missing schemaVersion; pass collect-signals output as the first file.');
  }
  if (!Array.isArray(codebase.routes) || !Array.isArray(codebase.findings) || !codebase.stack) {
    throw new Error('codebase.json must be scan-codebase output with stack, routes[], and findings[].');
  }

  return {
    ...signals,
    codebase: annotateCodebaseScan(signals, codebase),
  };
}

export function annotateCodebaseScan(signals, codebase) {
  const index = buildRouteMetricIndex(signals);
  return {
    ...codebase,
    findings: (codebase.findings ?? []).map((finding) => annotateFinding(finding, index)),
  };
}

function annotateFinding(finding, index) {
  if (!finding || typeof finding !== 'object') return finding;

View on GitHub (pinned to b8caa260a4)

Solutions

  1. Re-run scan-codebase to produce a complete codebase.json with stack, routes[], and findings[].
  2. Verify the second positional is the scan-codebase file, not the signals file.
  3. Inspect codebase.json and confirm all three fields are present and non-empty before merging.

Example fix

# before — second file is not scan-codebase output
$ node scripts/merge-signals.mjs signals.json partial.json
-> codebase.json must be scan-codebase output with stack, routes[], and findings[].

# after — regenerate and merge the complete scan
$ node scripts/scan-codebase.mjs . > codebase.json
$ node scripts/merge-signals.mjs signals.json codebase.json -o merged.json
Defensive patterns

Strategy: type-guard

Validate before calling

import { readFileSync } from 'node:fs';
function loadCodebase(path) {
  const c = JSON.parse(readFileSync(path, 'utf-8'));
  if (!Array.isArray(c.routes) || !Array.isArray(c.findings) || !c.stack) {
    throw new Error(`${path} is not scan-codebase output (needs stack, routes[], findings[])`);
  }
  return c;
}
const codebase = loadCodebase(process.argv[3]);

Type guard

function isScanCodebaseOutput(v) {
  return v !== null && typeof v === 'object' && !Array.isArray(v)
    && !!v.stack && Array.isArray(v.routes) && Array.isArray(v.findings);
}

Prevention

When it happens

Trigger: Passing a codebase.json that is actually collect-signals output; a truncated/empty scan-codebase run; a hand-authored file missing routes/findings/stack; a codebase scan that errored out and wrote a partial object.

Common situations: Files swapped (codebase slot holds signals); scan-codebase failed silently and wrote `{}`; an old codebase.json from before routes/findings were added to the schema.

Related errors


AI-assisted analysis of vercel-labs/agent-skills@b8caa260a4 (2026-08-13). Data as JSON: /api/errors/89d1e36a8c25d37e. Report an issue: GitHub.