{"record":{"id":"0a04b579091b9d70","repo":"affaan-m/ECC","slug":"refusing-to-replace-unowned-existing-file-desti","errorCode":null,"errorMessage":"Refusing to replace unowned existing file: ${destinationPath}","messagePattern":"Refusing to replace unowned existing file: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/multi-harness-setup.js","lineNumber":293,"sourceCode":"    const current = assertMergeDestination(destinationPath, destination);\n    if (ownedDestinations.has(canonicalDestination)) return 'managed-json-update';\n    const conflicts = findJsonConflicts(current, operation.mergePayload);\n    if (conflicts.length > 0) {\n      throw new Error(\n        `Refusing to overwrite unowned JSON fields at ${destinationPath}: ${conflicts.join(', ')}`\n      );\n    }\n    return 'json-merge';\n  }\n  if (ownedDestinations.has(canonicalDestination)) return 'managed-update';\n  if (\n    operation.kind === 'copy-file'\n    && typeof operation.sourcePath === 'string'\n    && readRegularFileSnapshot(operation.sourcePath)?.content.equals(destination.content)\n  ) {\n    return 'identical';\n  }\n  throw new Error(`Refusing to replace unowned existing file: ${destinationPath}`);\n}\n\nfunction writableRequirement(destinationPath) {\n  if (fs.existsSync(destinationPath)) {\n    const mode = fs.statSync(destinationPath).isDirectory()\n      ? fs.constants.W_OK | fs.constants.X_OK\n      : fs.constants.W_OK;\n    return { candidatePath: destinationPath, mode };\n  }\n\n  let candidatePath = path.dirname(destinationPath);\n  while (!fs.existsSync(candidatePath)) {\n    const parentPath = path.dirname(candidatePath);\n    if (parentPath === candidatePath) break;\n    candidatePath = parentPath;\n  }\n  return {\n    candidatePath,","sourceCodeStart":275,"sourceCodeEnd":311,"githubUrl":"https://github.com/affaan-m/ECC/blob/8321021c54d670126ce3b2969d5deb880b4b0c2a/scripts/lib/multi-harness-setup.js#L275-L311","documentation":"classifyManagedOperation throws this when the destination file already exists, is not an ECC-owned destination, and is not byte-identical to the operation's copy-file source. ECC will not replace a file it does not own with different content, since that could destroy user work. Only 'create' (missing file), 'managed-update' (owned), 'identical' (same bytes as source), and safe merges are permitted.","triggerScenarios":"Installing a copy-file operation where the destination file exists, ownedDestinations does not contain its canonical path, and destination content differs from operation.sourcePath content — e.g. installing into a repo that already has its own AGENTS.md/hooks/commands files.","commonSituations":"Project already defines its own AGENTS.md, hooks.json, or command files before installing ECC; re-installing after install-state was lost/deleted so previous files are no longer 'owned'; installing a newer ECC over files customized locally.","solutions":["Diff the existing file against the ECC source; if the existing content is disposable, delete or move it and re-run the install so ECC creates it fresh.","Merge your customizations into the ECC version of the file, then re-run so the content is identical or properly owned via a fresh install-state run.","Restore or regenerate the install-state (guided install) so previously installed files are recognized as owned before updating.","Keep project-specific files at paths ECC does not manage instead of editing managed files in place."],"exampleFix":"// before: repo's own AGENTS.md blocks install\nmv AGENTS.md AGENTS.project.md && ecc-install   // install creates ECC AGENTS.md\n// after: fold project notes into the managed file, or keep a separate file ECC never writes","handlingStrategy":"try-catch","validationCode":"if (fs.existsSync(destinationPath)\n  && !ownedDestinations.has(path.resolve(destinationPath))\n  && !fs.readFileSync(destinationPath).equals(fs.readFileSync(operation.sourcePath))) {\n  console.warn(`${destinationPath} exists and differs from ECC source; move or merge it before installing.`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await runInstall(plan);\n} catch (err) {\n  if (String(err.message).startsWith('Refusing to replace unowned existing file:')) {\n    const file = err.message.replace('Refusing to replace unowned existing file: ', '');\n    console.error(`Back up or merge ${file}, then re-run the install.`);\n  } else throw err;\n}","preventionTips":["Diff existing repo files against ECC sources before installing; move project-specific files to non-managed paths.","Never delete install-state and expect reinstalls to be no-ops; existing unowned files will block.","Fold customizations into the ECC-managed file via the guided flow so ownership is established.","Re-install only through the guided preview so ownership and content checks run in order."],"tags":["install","file-overwrite","ownership"],"backgroundTag":"file-already-exists","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"}