{"id":"47575a07e710229e","repo":"rust-lang/rust","slug":"failed-to-copy-src-dst-e","errorCode":null,"errorMessage":"failed to copy {src:?}->{dst:?}: {e}","messagePattern":"failed to copy (.+?)->(.+?): (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler/rustc_codegen_cranelift/build_system/utils.rs","lineNumber":222,"sourceCode":"            }\n        }\n    }\n}\n\npub(crate) fn copy_dir_recursively(from: &Path, to: &Path) {\n    for entry in fs::read_dir(from).unwrap() {\n        let entry = entry.unwrap();\n        let filename = entry.file_name();\n        if filename == \".\" || filename == \"..\" {\n            continue;\n        }\n        let src = from.join(&filename);\n        let dst = to.join(&filename);\n        if entry.metadata().unwrap().is_dir() {\n            fs::create_dir(&dst).unwrap_or_else(|e| panic!(\"failed to create {dst:?}: {e}\"));\n            copy_dir_recursively(&src, &dst);\n        } else {\n            fs::copy(&src, &dst).unwrap_or_else(|e| panic!(\"failed to copy {src:?}->{dst:?}: {e}\"));\n        }\n    }\n}\n\nstatic IN_GROUP: AtomicBool = AtomicBool::new(false);\npub(crate) struct LogGroup {\n    is_gha: bool,\n}\n\nimpl LogGroup {\n    pub(crate) fn guard(name: &str) -> LogGroup {\n        let is_gha = env::var(\"GITHUB_ACTIONS\").is_ok();\n\n        assert!(!IN_GROUP.swap(true, Ordering::SeqCst));\n        if is_gha {\n            eprintln!(\"::group::{name}\");\n        }\n","sourceCodeStart":204,"sourceCodeEnd":240,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_codegen_cranelift/build_system/utils.rs#L204-L240","documentation":"Panics inside copy_dir_recursively when fs::copy fails to copy a regular file from src to dst. Like error 60 this runs during the prepare stage that stages rustc sources into the build target. The panic halts staging because every source file is expected to copy cleanly.","triggerScenarios":"Reached for every non-directory entry while walking `from` during copy_dir_recursively. The panic message shows both src and dst plus the io::Error returned by std::fs::copy.","commonSituations":"src file is removed/renamed between read_dir and copy (TOCTOU, common with editor temp files or `.git` mutating underneath); dst is on a read-only or full filesystem; permission bits on src forbid reading (e.g. staged under a mode-0600 dir); cross-filesystem copy hits an immutable/append-only flag; antivirus/Defender locking the file on Windows.","solutions":["Re-run `./y.rs prepare` from a clean checkout so the source tree is not mutating during the copy.","Verify read permission on src: `ls -l <src>` (look for mode and owner).","Check the dst filesystem is writable and has free space: `df -h <dst>` and `touch <dst-dir>/.probe`.","On Windows, exclude the build directory from antivirus real-time scanning."],"exampleFix":"// before\nfs::copy(&src, &dst).unwrap_or_else(|e| panic!(\"failed to copy {src:?}->{dst:?}: {e}\"));\n// after\nfs::copy(&src, &dst).unwrap_or_else(|e| match e.kind() {\n    io::ErrorKind::AlreadyExists => { /* re-copy is fine, fall through */ fs::copy(&src, &dst).unwrap() }\n    _ => panic!(\"failed to copy {src:?}->{dst:?}: {e}\"),\n});","handlingStrategy":"validation","validationCode":"use std::path::Path;\nfn ensure_copyable(src: &Path, dst: &Path) -> Result<(), String> {\n    let sm = std::fs::metadata(src).map_err(|e| format!(\"src {:?} not readable: {}\", src, e))?;\n    if !sm.is_file() { return Err(format!(\"src {:?} is not a regular file\", src)); }\n    let parent = dst.parent().ok_or_else(|| format!(\"dst {:?} has no parent\", dst))?;\n    if !parent.exists() { return Err(format!(\"dst parent {:?} missing\", parent)); }\n    let pm = std::fs::metadata(parent).map_err(|e| format!(\"cannot stat dst parent: {}\", e))?;\n    if pm.permissions().readonly() { return Err(format!(\"dst parent {:?} is readonly\", parent)); }\n    if dst.exists() && dst.metadata().map(|m| m.permissions().readonly()).unwrap_or(false) {\n        return Err(format!(\"dst {:?} exists and is readonly\", dst));\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"use std::panic;\nmatch panic::catch_unwind(|| fs::copy(src, dst)) {\n    Ok(Ok(n)) => { /* copied n bytes */ }\n    Ok(Err(e)) => return Err(format!(\"io copy failed: {}\", e)),\n    Err(_)    => { /* remove partial dst, surface as fatal build error */ }\n}","preventionTips":["Verify src exists and is a regular file before triggering the copy.","Make sure the destination parent is writable and not on a full or readonly filesystem.","Avoid placing dst where a concurrent process may lock it (e.g. antivirus, indexer).","If a copy panics, delete the partial destination before retrying to avoid stale artifacts."],"tags":["build-system","filesystem","cg-clif","panic","io"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}