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

  1. 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
  2. If no rollback is needed, back up and delete the state file so readStateIfPresent() returns null and the next beginLegacySyncState() starts fresh
  3. Restore the state file from a backup written by the same ECC version
  4. 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

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


AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18). Data as JSON: /api/errors/06392d888ee51814. Report an issue: GitHub.