{"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":"validation","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/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/codex-legacy-sync.js#L134-L170","documentation":"parseState JSON-parses the legacy Codex sync state file and validates its shape: it must contain schema === SCHEMA and an Array paths. If the file exists but is not valid JSON, was written for a different schema version, or is corrupted/truncated, this error is thrown with the offending path. It guards downstream code that iterates state.paths unconditionally.","triggerScenarios":"Calling readState or readStateIfPresent on a state file whose parsed JSON has state.schema !== SCHEMA or state.paths is not an array — e.g. hand-edited state, truncated write, state produced by an older/newer plugin version with a different SCHEMA constant.","commonSituations":"Manually editing or minifying the state file; a partial write from a crash before the atomic temp-file rename; upgrading/downgrading the plugin so the embedded SCHEMA constant no longer matches the on-disk file; state file clobbered by another tool writing its own JSON.","solutions":["Inspect the state file (cat statePath) and fix or restore the expected { schema, paths: [...] } structure.","Delete the invalid state file and re-run the install so beginLegacySyncState writes a fresh, schema-correct snapshot.","If you intentionally changed SCHEMA, migrate the on-disk file to the new schema value and ensure paths is an array.","Reinstall the matching plugin version so the SCHEMA constant matches the state file that was written with it."],"exampleFix":"// before (hand-edited state.json)\n{ \"version\": 2, \"files\": [\"a\"] }\n// after\n{ \"schema\": \"<SCHEMA value from codex-legacy-sync.js>\", \"paths\": [{ \"path\": \"...\", \"installedSha256\": \"...\" }] }\n// or simply: rm state.json && rerun install","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nfunction looksLikeValidState(statePath) {\n  try {\n    const s = JSON.parse(fs.readFileSync(statePath, 'utf8'));\n    return typeof s.schema === 'string' && Array.isArray(s.paths);\n  } catch {\n    return false;\n  }\n}","typeGuard":"function isLegacySyncState(value) {\n  return (\n    typeof value === 'object' && value !== null &&\n    'schema' in value && typeof value.schema === 'string' &&\n    'paths' in value && Array.isArray(value.paths)\n  );\n}","tryCatchPattern":"let state;\ntry {\n  state = readState(statePath);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Invalid legacy Codex sync state')) {\n    fs.rmSync(statePath, { force: true }); // or archive it\n    state = beginLegacySyncState({ codexHome }); // regenerate\n  } else {\n    throw err;\n  }\n}","preventionTips":["Never hand-edit the state file; regenerate it via install instead.","Keep the plugin version constant between writing and reading state, or migrate the schema explicitly.","Check that writes completed (the atomic temp+rename pattern guards this) — inspect for truncated JSON after crashes.","Validate the file with a JSON parser before running update/rollback commands."],"tags":["schema-validation","json","state-management","codex"],"backgroundTag":"schema-validation-failed","analyzedSha":"8321021c54d670126ce3b2969d5deb880b4b0c2a","analyzedAt":"2026-09-16T10:08:13.343Z","contentChangedAt":"2026-09-16T10:08:13.343Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}