affaan-m/ECC · error · Error
Legacy Codex sync state requires recovery before reinstall:
Error message
Legacy Codex sync state requires recovery before reinstall: ${statePath} What it means
beginLegacySyncState() refuses to reinstall when the prior state's status is anything other than 'installed'. The sync flips status to 'applying' while work is in flight, so a non-installed status means a previous apply or rollback was interrupted and the recorded rollbackPaths may be half-applied; the operator must complete recovery before ECC touches the tree again.
Source
Thrown at scripts/lib/codex-legacy-sync.js:232
}
const digest = snapshot
? crypto.createHash('sha256').update(snapshot.content).digest('hex')
: null;
if (digest !== entry.installedSha256) {
throw new Error(`Refusing to replace modified legacy Codex artifact: ${filePath}`);
}
}
}
function beginLegacySyncState(options) {
const codexHome = path.resolve(options.codexHome);
const statePath = getStatePath(codexHome);
const configPath = path.join(codexHome, 'config.toml');
const agentsPath = path.join(codexHome, 'AGENTS.md');
const installedHooksPath = options.installedHooksPath ? path.resolve(options.installedHooksPath) : null;
const priorState = readStateIfPresent(statePath);
if (priorState && priorState.status !== 'installed') {
throw new Error(`Legacy Codex sync state requires recovery before reinstall: ${statePath}`);
}
if (priorState) assertInstalledStateUnmodified(priorState);
const trustedRoots = [...new Set([
codexHome,
...(Array.isArray(priorState?.trustedRoots) ? priorState.trustedRoots : []),
...(priorState?.installedHooksPath ? [priorState.installedHooksPath] : []),
...(installedHooksPath ? [installedHooksPath] : []),
].map(rootPath => path.resolve(rootPath)))];
const state = priorState ? {
...priorState,
status: 'applying',
updatedAt: new Date().toISOString(),
backupDir: options.backupDir ? path.resolve(options.backupDir) : priorState.backupDir,
installedHooksPath,
trustedRoots,
rollbackPreviousHooksPath: options.previousHooksPath || null,
rollbackPaths: priorState.paths.map(entry => snapshotLegacyPath(path.resolve(entry.path))),
previousInstalledState: priorState,View on GitHub (pinned to 06c5e118c4)
Solutions
- Run the legacy Codex sync rollback/recovery entry point (rollbackLegacyCodexSync restores rollbackPaths and clears the state) before reinstalling
- If recovery is unavailable, manually verify managed files are intact, back up and delete the state file, then reinstall fresh
- Re-run the original sync to completion if it stopped for a retryable reason (lock, transient error)
Example fix
// before: beginLegacySyncState throws Legacy Codex sync state requires recovery before reinstall
rollbackLegacyCodexSync({ statePath }); // finishes the interrupted work
beginLegacySyncState({ codexHome }); // now proceeds Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
function stateNeedsRecovery(statePath) {
try {
const prior = JSON.parse(fs.readFileSync(statePath, 'utf8'));
return typeof prior.status === 'string' && prior.status !== 'installed';
} catch { return false; }
}
if (stateNeedsRecovery(statePath)) runRecoveryFirst(); Type guard
const needsRecovery = (s) => s !== null && typeof s === 'object' && s.status !== undefined && s.status !== 'installed';
Try / catch
try { beginLegacySyncState({ codexHome }); }
catch (err) {
if (/requires recovery before reinstall/.test(err.message)) {
rollbackLegacyCodexSync({ statePath }).then(() => beginLegacySyncState({ codexHome }));
} else throw err;
} Prevention
- Let syncs finish; avoid Ctrl-C during apply
- Set CI timeouts above install duration
- Run the explicit rollback entry point when aborting a sync
When it happens
Trigger: A prior sync crashed or was Ctrl-C'd between writing status 'applying' and completing; an earlier rollback itself failed leaving a non-installed status; the next beginLegacySyncState() call throws immediately on readStateIfPresent().
Common situations: CI timeout killing the install mid-run; terminal closed or machine slept during apply; a rollback that hit a filesystem error and aborted.
Related errors
- Refusing to replace modified legacy Codex artifact: ${filePa
- Invalid ${flag}: expected a single cache path segment
- Unknown argument: ${arg}
- Missing value for ${arg}
- Failed to read ${filePath}: ${error.message}
AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18).
Data as JSON: /api/errors/fcf13dd9cb248c2f.
Report an issue: GitHub.