Fission-AI/OpenSpec · error
RENAMED failed for header "### Requirement: " - target…
Error message
${specName} RENAMED failed for header "### Requirement: ${r.to}" - target already exists What it means
Thrown in buildUpdatedSpec during RENAMED application when the FROM header is missing from the baseline but the TO header already exists and no case/whitespace variant of the source remains. That combination means the rename's source was consumed while its target is present, yet the guard for typo'd sources found nothing — the collision is reported as a target conflict.
Solutions
- Remove the RENAMED entry — the rename appears to have been applied already
- Check whether a different FROM header was intended and correct it
Defensive patterns
Strategy: validation
When it happens
Trigger: Thrown at src/core/specs-apply.ts:403 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of Fission-AI/OpenSpec@6926ccb18a (2026-08-25).
Data as JSON: /api/errors/fbd94b04ab567327.
Report an issue: GitHub.
Appendix: source
Thrown at src/core/specs-apply.ts:403
// not a failure. Only a missing source AND target is a genuine error.
if (nameToBlock.has(to)) {
// Unless a case/whitespace variant of the source still exists (and is
// not the target itself, as in a case-only rename): that is a typo'd
// header, not an early-synced rename — same guard REMOVED applies.
const nearMiss = [...nameToBlock.keys()].find(
(k) => k !== to && foldRequirementName(k) === foldRequirementName(from)
);
if (nearMiss !== undefined) {
throw new Error(
`${specName} RENAMED failed for header "### Requirement: ${r.from}" - source not found, but "### Requirement: ${nameToBlock.get(nearMiss)!.name}" exists; fix the header to match it exactly`
);
}
continue;
}
throw new Error(`${specName} RENAMED failed for header "### Requirement: ${r.from}" - source not found`);
}
if (nameToBlock.has(to)) {
throw new Error(`${specName} RENAMED failed for header "### Requirement: ${r.to}" - target already exists`);
}
const block = nameToBlock.get(from)!;
const newHeader = `### Requirement: ${to}`;
const rawLines = block.raw.split('\n');
rawLines[0] = newHeader;
const renamedBlock: RequirementBlock = {
headerLine: newHeader,
name: to,
raw: rawLines.join('\n'),
};
nameToBlock.delete(from);
nameToBlock.set(to, renamedBlock);
renamedTargets.set(from, to);
renamedApplied++;
}
// REMOVED
let removedApplied = 0;View on GitHub (pinned to 6926ccb18a)