affaan-m/ECC · error · Error
Legacy sync path changed before removal; preserved replaceme
Error message
Legacy sync path changed before removal; preserved replacement at ${quarantinePath} What it means
removeOpenedRegularFile deletes safely by first hardlinking the opened file into a quarantine temp dir, unlinking the original, then comparing dev/ino of the opened descriptor against the quarantined copy. If they differ, the path was replaced between open and removal (error 98's situation) — and in this branch the attempted restore (linking the quarantined original back to the path) also failed. The replacement file currently sitting at the path is left intact, and the original content is preserved at the reported quarantine path so nothing is lost.
Source
Thrown at scripts/lib/codex-legacy-sync.js:121
}
function removeOpenedRegularFile(filePath, opened) {
const quarantineDir = fs.mkdtempSync(path.join(path.dirname(filePath), '.ecc-remove-'));
const quarantinePath = path.join(quarantineDir, path.basename(filePath));
fs.renameSync(filePath, quarantinePath);
const quarantined = openRegularFileNoFollow(quarantinePath);
const openedStat = fs.fstatSync(opened.descriptor, { bigint: true });
const quarantinedStat = fs.fstatSync(quarantined.descriptor, { bigint: true });
fs.closeSync(quarantined.descriptor);
fs.closeSync(opened.descriptor);
opened.descriptor = null;
if (quarantinedStat.dev !== openedStat.dev || quarantinedStat.ino !== openedStat.ino) {
try {
fs.linkSync(quarantinePath, filePath);
fs.unlinkSync(quarantinePath);
fs.rmdirSync(quarantineDir);
} catch (_restoreError) {
throw new Error(
`Legacy sync path changed before removal; preserved replacement at ${quarantinePath}`
);
}
throw new Error(`Legacy sync path changed before removal: ${filePath}`);
}
fs.unlinkSync(quarantinePath);
fs.rmdirSync(quarantineDir);
}
function atomicWriteJson(filePath, value) {
fs.mkdirSync(path.dirname(filePath), { recursive: true, mode: 0o700 });
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
fs.writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
fs.renameSync(tempPath, filePath);
}
function readState(statePath) {
const snapshot = readRegularFileNoFollow(statePath, 'utf8');View on GitHub (pinned to 06c5e118c4)
Solutions
- Copy your data out of the preserved original at the reported quarantine path, then decide which version should win.
- Delete the quarantine directory (.ecc-remove-*) once recovered.
- Eliminate the concurrent writer (single sync job, locking) so the swap cannot recur.
Example fix
# before # Error: ...preserved replacement at ~/.codex/.ecc-remove-XXXXXX/state.json # after — recover the preserved original, drop quarantine $ cp ~/.codex/.ecc-remove-*/state.json ~/state-recovered.json $ rm -rf ~/.codex/.ecc-remove-*
Defensive patterns
Strategy: fallback
Try / catch
try { removeLegacyState(statePath); } catch (e) {
const m = e.message.match(/preserved replacement at (.+)$/);
if (m) {
console.error(`Original preserved at ${m[1]} — recovering content, replacement kept at ${statePath}`);
fs.copyFileSync(m[1], backupPath);
fs.rmSync(path.dirname(m[1]), { recursive: true, force: true });
} else throw e;
} Prevention
- Serialize state-file removals so no other process can swap the path mid-delete.
- Watch for .ecc-remove-* quarantine dirs after failed syncs — they hold the preserved original.
When it happens
Trigger: A concurrent process renames a new file over the state path while removal is in flight, and simultaneously the state directory's permissions or another failure prevents the quarantine hardlink from being linked back.
Common situations: Parallel sync processes fighting over the same state file on a permission-restricted directory; cleanup daemons recreating state files mid-delete.
Related errors
- Legacy sync path changed while opening: ${filePath}
- Refusing to create non-regular legacy sync path: ${filePath}
- Legacy sync path changed before removal: ${filePath}
- Refusing to manage non-regular legacy sync path: ${filePath}
- Legacy Codex sync state not found at ${statePath}
AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18).
Data as JSON: /api/errors/e85140edd5923bae.
Report an issue: GitHub.