{"record":{"id":"b4ccdc3e3dfa42bf","repo":"vercel/turborepo","slug":"path-component-contains-nul-byte-component","errorCode":null,"errorMessage":"path component contains NUL byte: {component:?}","messagePattern":"path component contains NUL byte: (.+?)","errorType":"exception","errorClass":"CacheError","httpStatus":null,"severity":"error","filePath":"crates/turborepo-cache/src/cache_archive/create.rs","lineNumber":504,"sourceCode":"        if len == -1 {\n            return Err(std::io::Error::last_os_error().into());\n        }\n\n        let len = len as usize;\n        if len < buffer.len() {\n            buffer.truncate(len);\n            let target = PathBuf::from(std::ffi::OsString::from_vec(buffer));\n            return Ok(camino::Utf8PathBuf::try_from(target).map_err(turbopath::PathError::from)?);\n        }\n\n        buffer.resize(buffer.len() * 2, 0);\n    }\n}\n\n#[cfg(unix)]\nfn path_component_cstring(component: &str) -> Result<std::ffi::CString, CacheError> {\n    std::ffi::CString::new(component).map_err(|_| {\n        std::io::Error::new(\n            std::io::ErrorKind::InvalidInput,\n            format!(\"path component contains NUL byte: {component:?}\"),\n        )\n        .into()\n    })\n}\n\n#[cfg(unix)]\nfn create_header_from_stat(file_info: &libc::stat) -> Result<Header, CacheError> {\n    let mut header = Header::new_gnu();\n    header.set_mode(unix_mode_to_u32(file_info.st_mode));\n\n    let file_type = file_info.st_mode & libc::S_IFMT;\n    if file_type == libc::S_IFLNK {\n        header.set_entry_type(EntryType::Symlink);\n        header.set_size(0);\n    } else if file_type == libc::S_IFDIR {\n        header.set_entry_type(EntryType::Directory);","sourceCodeStart":486,"sourceCodeEnd":522,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-cache/src/cache_archive/create.rs#L486-L522","documentation":"While building a cache archive tar, turborepo walks the tree with openat/fstatat/readlinkat relative to a parent fd, and each single path component must be converted to a C string first (crates/turborepo-cache/src/cache_archive/create.rs:502, used at lines 423/438/453/475). This error means one component contained an embedded NUL byte, which CString::new rejects. On Unix a real filesystem name can never contain NUL, so this is a defensive guard against in-memory or corrupted names, not a normal runtime condition.","triggerScenarios":"Cache archive creation (save-to-cache) reaching open_dir_at / open_file_at / fstatat_no_follow / read_link_at with a component string that contains a '\\0' — i.e. a component that did not come straight from a healthy readdir, or a readdir buffer that is corrupt.","commonSituations":"Essentially never seen on healthy systems. When it appears it points to data corruption (bad readdir, memory bug) or a path synthesized from untrusted bytes that smuggled in a NUL.","solutions":["Re-run the task once to rule out transient corruption; if it reproduces, the tree really has an offending entry","Inspect the traced directory with `ls -b` or `find <dir> -print0 | tr -c '\\000\\n' '?'` to spot non-printable/NUL-containing names and rename or delete them","If it only reproduces on a cache hit replay, clear the local and remote turbo cache and rebuild","Report a bug with the exact path from the message — on Unix this should be unreachable"],"exampleFix":"# shell: find the offending name\nfind . -name '*' -print0 | tr -c '\\000\\n' '?\\n' | grep -B1 '?'\n# rename or remove the file it flags, then re-run:\nnpx turbo run build --force","handlingStrategy":"validation","validationCode":"// before walking a tree into the cache archive, reject NUL components\nfn components_ok(path: &camino::Utf8Path) -> bool {\n    path.components().all(|c| !c.as_str().contains('\\0'))\n}\nassert!(components_ok(&path));","typeGuard":"fn is_nul_free(p: &str) -> bool { !p.contains('\\0') }","tryCatchPattern":"match result {\n    Err(CacheError::Io(e)) if e.kind() == std::io::ErrorKind::InvalidInput\n        && e.to_string().contains(\"NUL byte\") => { /* skip entry, log path */ }\n    other => other?,\n}","preventionTips":["Never build path components from raw untrusted bytes without validating them","Treat a NUL-component hit as corruption: stop and investigate instead of retrying"],"tags":["tar","cache","unix","path","nul-byte"],"backgroundTag":"invalid-path-characters","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}