Kuberwastaken/claurst · error
installed binary path has no file name
Error message
installed binary path has no file name: {} What it means
create_next_to called Path::file_name() on the installed binary path and got None, meaning the path terminates in '..' or is the filesystem root. The upgrader needs the original file name to name the staged replacement binary. This is essentially an invariant violation: an executable path should always have a final component.
Solutions
- Canonicalize the binary path before staging so '..' components are resolved away.
- Reinstall the binary at a normal absolute path with a real file name.
- Inspect how the binary is being launched (wrapper scripts, symlinks) and fix the path.
- Fall back to installing to a default bin directory if the current path is unusable.
Example fix
// before let current = std::env::current_exe()?; // after let current = std::env::current_exe()?.canonicalize()?;
Defensive patterns
Strategy: validation
Validate before calling
// canonicalize to eliminate '..' and root-only paths
let current = std::env::current_exe()?.canonicalize()?;
if current.file_name().is_none() {
bail!("cannot determine binary file name from {}", current.display());
} Prevention
- Always canonicalize current_exe before path decomposition
- Avoid symlink chains ending in '..' components for the install path
- Reinstall via the official installer so the path has a real final component
When it happens
Trigger: The resolved current-exe path ends with '..' or is root ('/'), so file_name() returns None in create_next_to during run_upgrade's staging step.
Common situations: Symlink chains or canonicalization producing a trailing '..' component; binary path set to '/' via misconfiguration; exotic container/sandbox mount layouts; manually hacked install location.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/4cc30187eb119b63.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/cli/src/upgrade.rs:316
path: PathBuf,
}
#[cfg(unix)]
impl StagedBinary {
fn create_next_to(current: &Path) -> Result<(Self, std::fs::File)> {
use std::ffi::OsString;
use std::fs::OpenOptions;
use std::io::ErrorKind;
use std::sync::atomic::{AtomicU64, Ordering};
static NEXT_STAGE_ID: AtomicU64 = AtomicU64::new(0);
const MAX_ATTEMPTS: usize = 128;
let parent = current
.parent()
.ok_or_else(|| anyhow!("installed binary path has no parent: {}", current.display()))?;
let file_name = current.file_name().ok_or_else(|| {
anyhow!(
"installed binary path has no file name: {}",
current.display()
)
})?;
for _ in 0..MAX_ATTEMPTS {
let id = NEXT_STAGE_ID.fetch_add(1, Ordering::Relaxed);
let mut staged_name = OsString::from(".");
staged_name.push(file_name);
staged_name.push(format!(".upgrade-{}-{}", std::process::id(), id));
let path = parent.join(staged_name);
match OpenOptions::new().write(true).create_new(true).open(&path) {
Ok(file) => return Ok((Self { path }, file)),
Err(error) if error.kind() == ErrorKind::AlreadyExists => continue,
Err(error) => {
return Err(error).with_context(|| {
format!(View on GitHub (pinned to b0637c97ec)