{"record":{"id":"d1c40a30d9c9d495","repo":"sinelaw/fresh","slug":"alreadyexists","errorCode":"AlreadyExists","errorMessage":"could not create a private staging file next to the target","messagePattern":"could not create a private staging file next to the target","errorType":"error_code","errorClass":"UpdateError","httpStatus":null,"severity":"error","filePath":"crates/fresh-update/src/self_update.rs","lineNumber":139,"sourceCode":"    let name = target\n        .file_name()\n        .map(|n| n.to_string_lossy().into_owned())\n        .unwrap_or_else(|| \"fresh\".to_string());\n    let dir = target.parent().unwrap_or_else(|| Path::new(\".\"));\n    for attempt in 0..16u32 {\n        let nonce = std::time::SystemTime::now()\n            .duration_since(std::time::UNIX_EPOCH)\n            .map(|d| d.subsec_nanos())\n            .unwrap_or(0)\n            ^ attempt.wrapping_mul(0x9E37_79B9);\n        let path = dir.join(format!(\".{name}.new-{nonce:08x}\"));\n        match create_exclusive(&path) {\n            Ok(file) => return Ok((path, file)),\n            Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists => continue,\n            Err(e) => return Err(UpdateError::Io(e)),\n        }\n    }\n    Err(UpdateError::Io(std::io::Error::new(\n        std::io::ErrorKind::AlreadyExists,\n        \"could not create a private staging file next to the target\",\n    )))\n}\n\n#[cfg(unix)]\nfn create_exclusive(path: &Path) -> std::io::Result<std::fs::File> {\n    use std::os::unix::fs::OpenOptionsExt;\n    std::fs::OpenOptions::new()\n        .write(true)\n        .create_new(true)\n        .custom_flags(libc::O_NOFOLLOW)\n        .mode(0o600)\n        .open(path)\n}\n\n#[cfg(not(unix))]\nfn create_exclusive(path: &Path) -> std::io::Result<std::fs::File> {","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/sinelaw/fresh/blob/67894ca5463dbd7a89bb31add4627c27d6b79d83/crates/fresh-update/src/self_update.rs#L121-L157","documentation":"`staging_file` retries `N` times to `create` a new exclusive staging file next to the target; if every attempt collides with an existing file, it gives up with `io::ErrorKind::AlreadyExists`. This should be near-impossible and usually means the filesystem is misbehaving or the naming scheme collides persistently.","triggerScenarios":"All attempted staging filenames (e.g. `.target.tmp-N`) already exist and `create_exclusive` keeps failing with AlreadyExists across the retry loop; the target directory contains many stale staging files; a filesystem that does not honor O_EXCL.","commonSituations":"Read-only or weird-FS mounts where create behaves unexpectedly; leftover staging files from crashed updates exhausting the name space; a malicious actor pre-creating predictable staging names next to a setuid binary.","solutions":["Inspect the target directory and delete stale `.tmp` staging files left by crashed updates","Check filesystem type/mount options support exclusive creation (O_EXCL)","Increase the retry count or use random/uuid-based staging names to avoid collisions","Ensure the update process has write permission to the target directory"],"exampleFix":"// before\nlet name = format!(\"{}.tmp-{}\", target_name, i);\n// after\nlet name = format!(\"{}.tmp-{}-{}\", target_name, std::process::id(), uuid::Uuid::new_v4().simple());","handlingStrategy":"retry","validationCode":"// preflight: check writability and clean stale staging files\nfor entry in std::fs::read_dir(target.parent().unwrap())? {\n    let p = entry?.path();\n    if p.to_string_lossy().contains(\".tmp\") && is_stale(&p) { let _ = std::fs::remove_file(p); }\n}","typeGuard":null,"tryCatchPattern":"match staging_file(&target) {\n    Err(UpdateError::Io(e)) if e.kind() == io::ErrorKind::AlreadyExists => {\n        // fall back to temp-dir staging or abort with a clear user message\n    }\n    other => other?,\n}","preventionTips":["Use random/uuid staging names to make collisions improbable","Clean up staging files on crash/exit (drop guards)","Verify the target directory is writable before updating","Alert the user if exclusivity repeatedly fails (possible tampering or FS limitations)"],"tags":["io","filesystem","self-update","atomic-write"],"backgroundTag":"file-already-exists","analyzedSha":"67894ca5463dbd7a89bb31add4627c27d6b79d83","analyzedAt":"2026-09-13T15:04:03.701Z","contentChangedAt":"2026-09-13T15:04:03.701Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}