affaan-m/ECC · error · Error
Invalid legacy Codex sync state at ${statePath}
Error message
Invalid legacy Codex sync state at ${statePath} What it means
Thrown by parseState() in the legacy Codex sync helper when the sync-state file (codexHome/ecc/legacy-sync-state.json) parses as JSON but does not match the expected shape: state.schema must equal the SCHEMA constant ('ecc.codex-legacy-sync.v1') and state.paths must be an array. The state file is ECC's bookkeeping of which files it installed into the Codex home; an unrecognized shape means rollback/reinstall cannot be trusted, so the sync aborts.
Source
Thrown at scripts/lib/codex-legacy-sync.js:152
fs.writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
fs.renameSync(tempPath, filePath);
}
function readState(statePath) {
const snapshot = readRegularFileNoFollow(statePath, 'utf8');
if (!snapshot) throw new Error(`Legacy Codex sync state not found at ${statePath}`);
return parseState(snapshot.content, statePath);
}
function readStateIfPresent(statePath) {
const snapshot = readRegularFileNoFollow(statePath, 'utf8');
return snapshot ? parseState(snapshot.content, statePath) : null;
}
function parseState(content, statePath) {
const state = JSON.parse(content);
if (state.schema !== SCHEMA || !Array.isArray(state.paths)) {
throw new Error(`Invalid legacy Codex sync state at ${statePath}`);
}
return state;
}
function hasUnsafeManagedAncestor(filePath, codexHome) {
const relativePath = path.relative(codexHome, filePath);
if (relativePath === '' || relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
return relativePath !== '';
}
const segments = relativePath.split(path.sep).slice(0, -1);
let currentPath = codexHome;
for (const segment of [null, ...segments]) {
if (segment !== null) currentPath = path.join(currentPath, segment);
try {
const stat = fs.lstatSync(currentPath);
if (stat.isSymbolicLink() || !stat.isDirectory()) return true;
} catch (error) {
if (error.code === 'ENOENT') break;View on GitHub (pinned to 06c5e118c4)
Solutions
- Inspect the state file at <codexHome>/ecc/legacy-sync-state.json and compare its schema field with SCHEMA ('ecc.codex-legacy-sync.v1') in scripts/lib/codex-legacy-sync.js
- If no rollback is needed, back up and delete the state file so readStateIfPresent() returns null and the next beginLegacySyncState() starts fresh
- Restore the state file from a backup written by the same ECC version
- Pin the ECC version that wrote the file, run its rollback flow, then upgrade and reinstall
Example fix
// before: state file left by a mismatched ECC version -> Invalid legacy Codex sync state
fs.copyFileSync(statePath, statePath + '.bak');
fs.rmSync(statePath, { force: true });
beginLegacySyncState({ codexHome }); // readStateIfPresent() now returns null, sync starts fresh Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
function stateFileIsUsable(statePath, expectedSchema) {
let raw;
try { raw = fs.readFileSync(statePath, 'utf8'); } catch { return true; } // absent state is fine
let state;
try { state = JSON.parse(raw); } catch { return false; }
return state.schema === expectedSchema && Array.isArray(state.paths);
} Type guard
function isLegacySyncState(v) {
return v !== null && typeof v === 'object'
&& typeof v.schema === 'string'
&& Array.isArray(v.paths)
&& v.paths.every(e => e !== null && typeof e === 'object' && typeof e.path === 'string');
} Try / catch
try {
beginLegacySyncState({ codexHome });
} catch (err) {
if (/Invalid legacy Codex sync state/.test(err.message)) {
// back up the state file, then remove it and start a fresh sync
} else throw err;
} Prevention
- Never hand-edit the sync-state JSON
- Run rollback before upgrading ECC while a sync is active
- Keep the same ECC version on machines that share CODEX_HOME
When it happens
Trigger: Calling readState()/beginLegacySyncState() when the state file has a schema value from a different ECC version (e.g. a future 'v2'), or paths is missing or not an array (e.g. {}, or paths: {"0": ...} after a hand edit or a bad merge).
Common situations: Upgrading/downgrading ECC across a state-format change; manually editing or reformatting the state JSON; a truncated-but-still-valid JSON write; copying CODEX_HOME between machines running different ECC versions.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Failed to read ${filePath}: ${error.message}
- finalize requires --state
- Invalid install config ${resolvedPath}: ${formatValidationEr
- Managed Claude install-state is invalid at ${statePath}
- Invalid ECC repo root: unreadable package.json at ${packageJ
AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18).
Data as JSON: /api/errors/06392d888ee51814.
Report an issue: GitHub.