{"record":{"id":"06392d888ee51814","repo":"affaan-m/ECC","slug":"invalid-legacy-codex-sync-state-at-statepath","errorCode":null,"errorMessage":"Invalid legacy Codex sync state at ${statePath}","messagePattern":"Invalid legacy Codex sync state at (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/codex-legacy-sync.js","lineNumber":152,"sourceCode":"  fs.writeFileSync(tempPath, `${JSON.stringify(value, null, 2)}\\n`, { mode: 0o600 });\n  fs.renameSync(tempPath, filePath);\n}\n\nfunction readState(statePath) {\n  const snapshot = readRegularFileNoFollow(statePath, 'utf8');\n  if (!snapshot) throw new Error(`Legacy Codex sync state not found at ${statePath}`);\n  return parseState(snapshot.content, statePath);\n}\n\nfunction readStateIfPresent(statePath) {\n  const snapshot = readRegularFileNoFollow(statePath, 'utf8');\n  return snapshot ? parseState(snapshot.content, statePath) : null;\n}\n\nfunction parseState(content, statePath) {\n  const state = JSON.parse(content);\n  if (state.schema !== SCHEMA || !Array.isArray(state.paths)) {\n    throw new Error(`Invalid legacy Codex sync state at ${statePath}`);\n  }\n  return state;\n}\n\nfunction hasUnsafeManagedAncestor(filePath, codexHome) {\n  const relativePath = path.relative(codexHome, filePath);\n  if (relativePath === '' || relativePath.startsWith('..') || path.isAbsolute(relativePath)) {\n    return relativePath !== '';\n  }\n  const segments = relativePath.split(path.sep).slice(0, -1);\n  let currentPath = codexHome;\n  for (const segment of [null, ...segments]) {\n    if (segment !== null) currentPath = path.join(currentPath, segment);\n    try {\n      const stat = fs.lstatSync(currentPath);\n      if (stat.isSymbolicLink() || !stat.isDirectory()) return true;\n    } catch (error) {\n      if (error.code === 'ENOENT') break;","sourceCodeStart":134,"sourceCodeEnd":170,"githubUrl":"https://github.com/affaan-m/ECC/blob/06c5e118c4d3e6c3b7f9445f973a2194c82de193/scripts/lib/codex-legacy-sync.js#L134-L170","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":"// before: state file left by a mismatched ECC version -> Invalid legacy Codex sync state\nfs.copyFileSync(statePath, statePath + '.bak');\nfs.rmSync(statePath, { force: true });\nbeginLegacySyncState({ codexHome }); // readStateIfPresent() now returns null, sync starts fresh","handlingStrategy":"validation","validationCode":"const fs = require('fs');\nfunction stateFileIsUsable(statePath, expectedSchema) {\n  let raw;\n  try { raw = fs.readFileSync(statePath, 'utf8'); } catch { return true; } // absent state is fine\n  let state;\n  try { state = JSON.parse(raw); } catch { return false; }\n  return state.schema === expectedSchema && Array.isArray(state.paths);\n}","typeGuard":"function isLegacySyncState(v) {\n  return v !== null && typeof v === 'object'\n    && typeof v.schema === 'string'\n    && Array.isArray(v.paths)\n    && v.paths.every(e => e !== null && typeof e === 'object' && typeof e.path === 'string');\n}","tryCatchPattern":"try {\n  beginLegacySyncState({ codexHome });\n} catch (err) {\n  if (/Invalid legacy Codex sync state/.test(err.message)) {\n    // back up the state file, then remove it and start a fresh sync\n  } else throw err;\n}","preventionTips":["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"],"tags":["codex","sync-state","json","schema-validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"06c5e118c4d3e6c3b7f9445f973a2194c82de193","analyzedAt":"2026-08-18T11:27:13.915Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}