Hmbown/CodeWhale · error
Refusing to replace : the update target is not a regular…
Error message
Refusing to replace {}: the update target is not a regular file.
{GITHUB_MIGRATION_HELP} What it means
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.
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.
Example fix
// before $ ln -s /opt/codewhale/bin/codewhale ~/.local/bin/codewhale && codewhale update # refused // after $ cp /opt/codewhale/bin/codewhale ~/.local/bin/codewhale && codewhale update
Defensive patterns
Strategy: validation
Validate before calling
fn is_regular_file(p: &std::path::Path) -> bool {
matches!(std::fs::symlink_metadata(p), Ok(m) if m.is_file() && !m.is_symlink())
} Type guard
fn is_regular_non_symlink(md: &std::fs::Metadata) -> bool {
md.is_file() && !md.is_symlink()
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Android loaded image
- built-in plugin path may not be a symbolic link or reparse…
- CodewhalePet/1
- could not securely open
- external credential path must name a non-reparse regular…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/0f9a1ba3f3c8cf40.
Report an issue: GitHub.
Appendix: source
Thrown at crates/cli/src/update.rs:583
fn validate_update_target(target: &Path, identity: &UpdateExecutableIdentity) -> Result<()> {
if !InstallMethod::from_path(target).supports_self_update() || protected_update_path(target) {
bail!(
"Refusing to replace managed/system path {}.\n\n{GITHUB_MIGRATION_HELP}",
target.display()
);
}
let metadata = match std::fs::symlink_metadata(target) {
Ok(metadata) => metadata,
Err(error) if error.kind() == std::io::ErrorKind::NotFound && target != identity.path => {
return Ok(());
}
Err(error) => {
return Err(error)
.with_context(|| format!("failed to inspect update target {}", target.display()));
}
};
if !metadata.is_file() || metadata.is_symlink() {
bail!(
"Refusing to replace {}: the update target is not a regular file.\n\n{GITHUB_MIGRATION_HELP}",
target.display()
);
}
let bytes = std::fs::read(target)
.with_context(|| format!("failed to identify update target {}", target.display()))?;
if sha256_hex(&bytes) != identity.file_hash {
bail!(
"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}",
target.display()
);
}
Ok(())
}
fn protected_update_path(path: &Path) -> bool {
[
"/usr/bin",View on GitHub (pinned to 73e0f67d83)