Egonex-AI/Understand-Anything · error · Error

Symbol baseline file inventory does not match the incrementa

Error message

Symbol baseline file inventory does not match the incremental plan

What it means

After the version/commit checks pass, `loadSymbolContext` cross-checks the baseline's file inventory against the plan: the sorted list of `baseline.files[].filePath` must exactly equal the plan's `filesToReanalyze`, every path must normalize non-empty, no path may appear in `plan.deletedFiles`, and there must be no duplicates. Any deviation throws this error, since symbol validation is only sound when both files agree on exactly which files to re-analyze.

Source

Thrown at understand-anything-plugin/skills/understand/validate-incremental-symbols.mjs:301

  };
}

export function git(root, args) {
  const result = spawnSync('git', args, { cwd: root, encoding: 'utf8', maxBuffer: 256 * 1024 * 1024 });
  if (result.status !== 0) throw new Error(`git ${args[0]} failed: ${result.stderr || result.error || result.status}`);
  return result.stdout;
}

export function loadSymbolContext(projectRoot, intermediateDir) {
  const plan = readJson(join(intermediateDir, 'incremental-plan.json'));
  const baseline = readJson(join(intermediateDir, 'incremental-symbol-baseline.json'));
  if (baseline.version !== 1 || baseline.baseCommit !== plan.baseCommit || baseline.headCommit !== plan.headCommit
    || !Array.isArray(baseline.files)) throw new Error('Symbol baseline does not match the incremental plan');
  const paths = baseline.files.map(file => file.filePath).sort();
  if (JSON.stringify(paths) !== JSON.stringify([...plan.filesToReanalyze].sort())
    || paths.some(path => !normalizePath(path) || (plan.deletedFiles ?? []).includes(path))
    || new Set(paths).size !== paths.length) {
    throw new Error('Symbol baseline file inventory does not match the incremental plan');
  }
  if (git(projectRoot, ['rev-parse', 'HEAD']).trim() !== plan.headCommit) {
    throw new Error('HEAD changed since prepare; baseline not advanced');
  }
  // Check every analyzer input, even if all IDs survive and parsing is skipped.
  // Git compares normalized contents, including repository clean/EOL rules.
  if (paths.length) git(projectRoot, [
    'diff', '--quiet', '--no-ext-diff', plan.headCommit, '--', ...paths.map(path => `:(literal)${path}`),
  ]);
  return { plan, baseline };
}

export async function validateIncrementalSymbols(projectRoot, { graph, intermediateDir } = {}) {
  const core = await getCore();
  intermediateDir ??= join(core.resolveUaDir(projectRoot), 'intermediate');
  const reportPath = join(intermediateDir, 'incremental-symbol-report.json');
  const report = { version: 1, ok: false, files: [], unresolvedFiles: [], errors: [] };
  const graphFromDisk = graph === undefined;

View on GitHub (pinned to 07edf82a04)

Solutions

  1. Regenerate the plan and baseline together by re-running the incremental prepare step; do not edit either file by hand.
  2. Diff `plan.filesToReanalyze` against `baseline.files[].filePath` to find the extra/missing entry and fix the prepare logic that produced it.
  3. Remove duplicate filePath entries from the baseline (or fix the dedupe in the generator).
  4. Ensure deleted files are excluded from filesToReanalyze and listed only in plan.deletedFiles.
  5. Verify file paths are stored in normalized (POSIX-style) form.

Example fix

// before: plan edited after baseline was written
plan.filesToReanalyze: ["src/a.ts", "src/b.ts"]
baseline.files: [{ filePath: "src/a.ts" }]

// after: regenerate baseline from the edited plan (or revert the plan edit)
# re-run prepare so baseline.files matches filesToReanalyze exactly
Defensive patterns

Strategy: validation

Validate before calling

const planPaths = [...plan.filesToReanalyze].sort();
const basePath = baseline.files.map(f => f.filePath).sort();
const inventoryOk = JSON.stringify(planPaths) === JSON.stringify(basePath)
  && new Set(basePath).size === basePath.length
  && basePath.every(p => typeof p === 'string' && p.length > 0)
  && !basePath.some(p => (plan.deletedFiles ?? []).includes(p));
if (!inventoryOk) rerunPrepareStep();

Type guard

function inventoriesMatch(plan, baseline) {
  const paths = baseline.files.map(f => f?.filePath).sort();
  return JSON.stringify(paths) === JSON.stringify([...plan.filesToReanalyze].sort())
    && new Set(paths).size === paths.length
    && paths.every(p => typeof p === 'string' && p.length > 0);
}

Try / catch

try {
  await validateIncrementalSymbols({ projectRoot, intermediateDir });
} catch (err) {
  if (err.message.includes('file inventory does not match')) {
    console.error('Plan/baseline inventory drift; regenerating artifacts');
    await rerunPrepareStep();
  } else throw err;
}

Prevention

When it happens

Trigger: Calling `loadSymbolContext` when `filesToReanalyze` and the baseline file list differ (missing/extra files), a baseline entry has an empty/invalid `filePath`, a planned file also appears in `deletedFiles`, or the baseline contains the same filePath twice.

Common situations: Someone edited `incremental-plan.json` to add/remove a file after the baseline was built; a merge of two intermediate directories produced duplicate entries; renamed files appear both in filesToReanalyze and deletedFiles; a path with Windows separators failed normalizePath.

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 Egonex-AI/Understand-Anything@07edf82a04 (2026-09-07). Data as JSON: /api/errors/fee2968eecefcfaa. Report an issue: GitHub.