Egonex-AI/Understand-Anything · error · Error
Current edge candidates do not match the incremental plan; r
Error message
Current edge candidates do not match the incremental plan; rerun merge
What it means
Before computing removed/retained nodes for the retry, the script checks that the persisted incremental-edge-candidates.json matches the current plan's baseCommit and headCommit and contains an edges array. A mismatch means the candidates file is from a different (older) incremental run, so it throws and instructs re-running the merge to regenerate candidates in sync with the plan.
Source
Thrown at understand-anything-plugin/skills/understand/prepare-symbol-retry.mjs:74
batch.previousSymbols = baseline.files.filter(file => files.has(file.filePath)).flatMap(file =>
file.nodes.filter(symbolKind).map(node => {
const parents = new Set(file.edges.filter(edge => edge.type === 'contains' && edge.target === node.id)
.map(edge => edge.source));
const owners = file.nodes.filter(parent => parent.type === 'class' && parents.has(parent.id))
.map(parent => parent.name);
return {
id: node.id, name: node.name, type: node.type, filePath: node.filePath,
...(node.lineRange ? { lineRange: node.lineRange } : {}),
...(owners.length ? { owners } : {}),
};
}),
);
batch.missingSymbols = report.files.filter(file => files.has(file.filePath));
}
const assembled = readJson(join(intermediateDir, 'assembled-graph.json'));
const candidates = readJson(join(intermediateDir, 'incremental-edge-candidates.json'));
if (candidates.baseCommit !== plan.baseCommit || candidates.headCommit !== plan.headCommit
|| !Array.isArray(candidates.edges)) throw new Error('Current edge candidates do not match the incremental plan; rerun merge');
const removedIds = new Set(assembled.nodes.filter(node => paths.has(normalizePath(node.filePath)))
.map(node => node.id));
const retainedIds = new Set(assembled.nodes.filter(node => !removedIds.has(node.id)).map(node => node.id));
const currentNodes = new Map(assembled.nodes.map(node => [node.id, node]));
const previousIds = new Set(baseline.files.filter(file => paths.has(file.filePath))
.flatMap(file => file.nodes.map(node => node.id)));
const targetsAffectedFile = id => removedIds.has(id) || previousIds.has(id)
|| (typeof id === 'string' && [...paths].some(path => id.includes(`:${path}:`)));
const sourceRemap = new Map(report.files.flatMap(file => file.replacements)
.map(({ oldId, newId }) => [oldId, newId]));
const inboundEdgeCandidates = [...assembled.edges, ...candidates.edges]
.map(edge => ({ ...edge, source: currentNodes.has(edge.source) ? edge.source : sourceRemap.get(edge.source) ?? edge.source })).filter(edge =>
retainedIds.has(edge.source) && targetsAffectedFile(edge.target));
const contextPaths = new Set(paths);
for (const edge of inboundEdgeCandidates) {
for (const id of [edge.source, edge.target]) {
if (currentNodes.has(id)) contextPaths.add(normalizePath(currentNodes.get(id).filePath));
}View on GitHub (pinned to 07edf82a04)
Solutions
- Re-run the incremental merge step so incremental-edge-candidates.json is regenerated for the current base/head commits.
- Clear stale intermediate files (incremental-edge-candidates.json) and re-run prepare-incremental.mjs followed by prepare-symbol-retry.mjs.
- Verify you are operating on the same commits as the plan — if HEAD moved, re-prepare the incremental plan first.
- Check plugin version consistency: old candidates schema (missing edges array) requires regenerating with the current version.
Example fix
// before: candidates from older run
// candidates: {baseCommit:'aaa', headCommit:'bbb'}, plan: {baseCommit:'aaa', headCommit:'ccc'} → throw
// after: regenerate candidates via merge
node prepare-incremental.mjs . # rewrites incremental-edge-candidates.json for current plan
node prepare-symbol-retry.mjs . Defensive patterns
Strategy: validation
Validate before calling
import { existsSync, readFileSync } from 'node:fs';
import { join } from 'node:path';
const candidatesPath = join(intermediateDir, 'incremental-edge-candidates.json');
if (!existsSync(candidatesPath)) throw new Error('Edge candidates missing; rerun merge');
const c = JSON.parse(readFileSync(candidatesPath, 'utf-8'));
if (c.baseCommit !== plan.baseCommit || c.headCommit !== plan.headCommit || !Array.isArray(c.edges)) {
throw new Error('Stale edge candidates; rerun incremental merge first');
} Type guard
const candidatesMatchPlan = (candidates, plan) => candidates && candidates.baseCommit === plan.baseCommit && candidates.headCommit === plan.headCommit && Array.isArray(candidates.edges);
Try / catch
try {
await runRetry(projectRoot);
} catch (e) {
if (e.message.includes('Current edge candidates do not match')) {
// rerun prepare-incremental.mjs to regenerate candidates for the current plan
} else throw e;
} Prevention
- Always run the incremental merge step before symbol retry so candidates match the plan.
- Clear stale intermediate files after commits advance or branches change.
- Record base/head commits in all intermediate artifacts and validate them together.
- Don't copy intermediate directories between machines or branches.
When it happens
Trigger: Running prepare-symbol-retry.mjs when incremental-edge-candidates.json was written for a different base/head commit pair than the loaded plan, was not produced by the merge step, or is missing the edges array (older schema or partial write).
Common situations: Leftover candidates file from a previous incremental run after commits advanced; interrupted merge step that never wrote candidates for the current plan; hand-copied intermediate state between machines/branches; older plugin version writing a different candidates schema.
Related errors
- Fingerprint patch does not match the incremental plan commit
- Project scan reported failures: ${preview}${suffix}
- Project scan omitted tracked, non-ignored files: ${unexplain
- Symbol retry requires a partial or architecture incremental
- Symbol retry already used for these commits; stop without ad
AI-assisted analysis of Egonex-AI/Understand-Anything@07edf82a04 (2026-09-07).
Data as JSON: /api/errors/52906b3a27740436.
Report an issue: GitHub.