{"record":{"id":"2a6e1cd684bd4bbe","repo":"affaan-m/ECC","slug":"refusing-to-replace-modified-legacy-codex-artifact","errorCode":null,"errorMessage":"Refusing to replace modified legacy Codex artifact: ${filePath}","messagePattern":"Refusing to replace modified legacy Codex artifact: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/codex-legacy-sync.js","lineNumber":212,"sourceCode":"  return {\n    path: filePath,\n    installedSha256: null,\n    previousType,\n    previousContentBase64: snapshot ? snapshot.content.toString('base64') : null,\n    previousMode: snapshot ? snapshot.mode : null,\n  };\n}\n\nfunction assertInstalledStateUnmodified(state) {\n  for (const entry of state.paths) {\n    const filePath = path.resolve(entry.path);\n    const trustedRoot = getTrustedRoot(state, filePath);\n    if (!trustedRoot || hasUnsafeManagedAncestor(filePath, trustedRoot)) {\n      throw new Error(`Refusing to reuse unsafe legacy Codex ownership path: ${filePath}`);\n    }\n    const snapshot = readRegularFileNoFollow(filePath);\n    if (!entry.installedSha256) {\n      if (snapshot) throw new Error(`Refusing to replace modified legacy Codex artifact: ${filePath}`);\n      continue;\n    }\n    const digest = snapshot\n      ? crypto.createHash('sha256').update(snapshot.content).digest('hex')\n      : null;\n    if (digest !== entry.installedSha256) {\n      throw new Error(`Refusing to replace modified legacy Codex artifact: ${filePath}`);\n    }\n  }\n}\n\nfunction beginLegacySyncState(options) {\n  const codexHome = path.resolve(options.codexHome);\n  const statePath = getStatePath(codexHome);\n  const configPath = path.join(codexHome, 'config.toml');\n  const agentsPath = path.join(codexHome, 'AGENTS.md');\n  const installedHooksPath = options.installedHooksPath ? path.resolve(options.installedHooksPath) : null;\n  const priorState = readStateIfPresent(statePath);","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/codex-legacy-sync.js#L194-L230","documentation":"assertInstalledStateUnmodified refuses to proceed when an entry in the sync state has NO installedSha256 (i.e. the artifact was recorded as previously absent) but the file now EXISTS on disk. Since the installer cannot verify the on-disk content matches what it wrote (there is no baseline digest), any existing file could be user-modified, so it aborts rather than overwriting user data.","triggerScenarios":"beginLegacySyncState -> assertInstalledStateUnmodified over a state entry without installedSha256 while readRegularFileNoFollow(filePath) returns a snapshot — i.e. the file was deleted at install time (recorded as absent) and has since been created by anything else (user, another tool, a later partial install).","commonSituations":"User restored a managed file from a backup after uninstalling; another plugin or dotfiles manager recreated the file; a failed previous install left the file behind without updating state; git checkout/branch switch restored the file.","solutions":["Compare the on-disk file with the intended artifact; if the content is yours and unwanted, delete or move it, then rerun the install.","Regenerate the sync state (delete statePath and reinstall) so the entry reflects the file's current hash instead of the 'absent' baseline.","If the file is legitimately the artifact (e.g. restored from the plugin), verify its sha256 matches the shipped artifact and update the state entry's installedSha256.","Back up the existing file before any deletion so user customizations are not lost."],"exampleFix":"// before: file exists but state has no installedSha256\nmv ~/.codex/AGENTS.md ~/.codex/AGENTS.md.user-backup\n// after: path is clear; rerun install, then merge any custom edits back manually","handlingStrategy":"validation","validationCode":"import fs from 'node:fs';\nfunction artifactAbsentEntryConflict(state, filePath) {\n  const entry = state.paths.find(e => path.resolve(e.path) === path.resolve(filePath));\n  return entry && !entry.installedSha256 && fs.existsSync(filePath);\n}","typeGuard":null,"tryCatchPattern":"try {\n  beginLegacySyncState(options);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith('Refusing to replace modified legacy Codex artifact')) {\n    const p = err.message.split('artifact: ')[1];\n    console.error(`Back up and remove your local copy of ${p}, then rerun install`);\n    process.exitCode = 1;\n  } else {\n    throw err;\n  }\n}","preventionTips":["Do not restore managed files from backups after uninstalling; reinstall instead.","Use the plugin's uninstall flow so state entries stay consistent with what is on disk.","Keep other dotfile/sync tools from writing into codexHome-managed paths.","Back up any unexpected file before deleting it to clear the conflict."],"tags":["checksum","state-management","data-loss-prevention","codex"],"backgroundTag":"checksum-mismatch","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"}