Fission-AI/OpenSpec · error
A concurrent file now occupies ; the displaced spec was…
Error message
${error instanceof Error ? error.message : String(error)} A concurrent file now occupies ${update.target}; the displaced spec was retained at ${displaced}. What it means
Thrown in the rollback path of deferred retirement: displaced-file verification failed (original error included), and while restoring state a new file was found occupying the target path. The displaced spec is preserved at the .openspec-retire-* path so no data is lost; both the original failure and the collision are reported.
Solutions
- Inspect the retained displaced file (path in message) and the concurrent occupant, and merge them manually
- Stop the concurrent writer before rerunning the archive
- Address the underlying verification error stated first in the message
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at src/core/specs-apply.ts:853 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/df172d54d15a981d.
Report an issue: GitHub.
Appendix: source
Thrown at src/core/specs-apply.ts:853
if (options.verifyDisplaced) {
const displaced = `${update.target}.openspec-retire-${randomUUID()}`;
displacedPath = displaced;
await fs.rename(update.target, displaced);
try {
await options.verifyDisplaced(displaced);
try {
await fs.lstat(update.target);
throw new Error(
`A concurrent file appeared at ${update.target} while archive was retiring it.`
);
} catch (targetError) {
if ((targetError as NodeJS.ErrnoException).code !== 'ENOENT') throw targetError;
}
if (!options.deferDelete) await fs.unlink(displaced);
} catch (error) {
try {
await fs.lstat(update.target);
throw new Error(
`${error instanceof Error ? error.message : String(error)} ` +
`A concurrent file now occupies ${update.target}; the displaced spec was retained at ${displaced}.`
);
} catch (targetError) {
if ((targetError as NodeJS.ErrnoException).code !== 'ENOENT') throw targetError;
}
await fs.rename(displaced, update.target);
throw error;
}
} else {
await fs.unlink(update.target);
}
} catch (error) {
if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { retired: false };
// A bare errno here reads as an internal failure; say what was being
// attempted so the message is actionable on its own.
throw new Error(
`Could not retire capability '${update.id}': failed to delete ${update.target} ` +View on GitHub (pinned to 6926ccb18a)