{"record":{"id":"0f9a1ba3f3c8cf40","repo":"Hmbown/CodeWhale","slug":"refusing-to-replace-the-update-target-is-not-a-regular-file","errorCode":null,"errorMessage":"Refusing to replace {}: the update target is not a regular file.\n\n{GITHUB_MIGRATION_HELP}","messagePattern":"Refusing to replace (.+?): the update target is not a regular file\\.\n\n(.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cli/src/update.rs","lineNumber":583,"sourceCode":"fn validate_update_target(target: &Path, identity: &UpdateExecutableIdentity) -> Result<()> {\n    if !InstallMethod::from_path(target).supports_self_update() || protected_update_path(target) {\n        bail!(\n            \"Refusing to replace managed/system path {}.\\n\\n{GITHUB_MIGRATION_HELP}\",\n            target.display()\n        );\n    }\n    let metadata = match std::fs::symlink_metadata(target) {\n        Ok(metadata) => metadata,\n        Err(error) if error.kind() == std::io::ErrorKind::NotFound && target != identity.path => {\n            return Ok(());\n        }\n        Err(error) => {\n            return Err(error)\n                .with_context(|| format!(\"failed to inspect update target {}\", target.display()));\n        }\n    };\n    if !metadata.is_file() || metadata.is_symlink() {\n        bail!(\n            \"Refusing to replace {}: the update target is not a regular file.\\n\\n{GITHUB_MIGRATION_HELP}\",\n            target.display()\n        );\n    }\n    let bytes = std::fs::read(target)\n        .with_context(|| format!(\"failed to identify update target {}\", target.display()))?;\n    if sha256_hex(&bytes) != identity.file_hash {\n        bail!(\n            \"Refusing to replace {}: its bytes differ from the running executable. This may be another installation or an unrelated command. No command is removed automatically.\\n\\n{GITHUB_MIGRATION_HELP}\",\n            target.display()\n        );\n    }\n    Ok(())\n}\n\nfn protected_update_path(path: &Path) -> bool {\n    [\n        \"/usr/bin\",","sourceCodeStart":565,"sourceCodeEnd":601,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/cli/src/update.rs#L565-L601","documentation":"The self-updater validates that the resolved update target is a regular file before replacing it. If symlink_metadata shows the target is a symlink, directory, or other non-regular file, it bails rather than clobbering whatever sits at that path. This prevents replacing launchers, aliases, or directories by mistake.","triggerScenarios":"run_update resolves a target path that is a symlink (even to the correct binary), a directory, or a device/socket; validate_update_target's `!metadata.is_file() || metadata.is_symlink()` check fires.","commonSituations":"User created a symlink named `codewhale` in ~/.local/bin pointing elsewhere; the install 'binary' is actually a wrapper script directory layout; the target was replaced by a desktop entry.","solutions":["Replace the symlink/wrapper with a real copy of the codewhale binary at the target path, then re-run update.","Point PATH at the directory containing the actual regular-file binary and run update from there.","Follow GITHUB_MIGRATION_HELP to reinstall cleanly into a supported location."],"exampleFix":"// before\n$ ln -s /opt/codewhale/bin/codewhale ~/.local/bin/codewhale && codewhale update  # refused\n// after\n$ cp /opt/codewhale/bin/codewhale ~/.local/bin/codewhale && codewhale update","handlingStrategy":"validation","validationCode":"fn is_regular_file(p: &std::path::Path) -> bool {\n    matches!(std::fs::symlink_metadata(p), Ok(m) if m.is_file() && !m.is_symlink())\n}","typeGuard":"fn is_regular_non_symlink(md: &std::fs::Metadata) -> bool {\n    md.is_file() && !md.is_symlink()\n}","tryCatchPattern":null,"preventionTips":["Keep the binary at the target path a real regular file, not a symlink or wrapper script","Avoid desktop-entry/alias layouts in the install directory"],"tags":["self-update","symlink","filesystem","safety-guard"],"backgroundTag":"invalid-argument-value","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}