{"record":{"id":"20a553c61f0bd85e","repo":"vercel/turborepo","slug":"windows-returned-invalid-utf-16-path-e","errorCode":null,"errorMessage":"Windows returned invalid UTF-16 path: {e}","messagePattern":"Windows returned invalid UTF-16 path: (.+?)","errorType":"exception","errorClass":"CacheError","httpStatus":null,"severity":"error","filePath":"crates/turborepo-cache/src/cache_archive/create.rs","lineNumber":664,"sourceCode":"\n    let mut buffer = vec![0u16; 260];\n    loop {\n        let len = unsafe {\n            GetFinalPathNameByHandleW(\n                file.as_raw_handle(),\n                buffer.as_mut_ptr(),\n                buffer.len() as u32,\n                FILE_NAME_NORMALIZED | VOLUME_NAME_DOS,\n            )\n        };\n        if len == 0 {\n            return Err(std::io::Error::last_os_error().into());\n        }\n\n        let len = len as usize;\n        if len < buffer.len() {\n            let path = String::from_utf16(&buffer[..len]).map_err(|e| {\n                std::io::Error::new(\n                    std::io::ErrorKind::InvalidData,\n                    format!(\"Windows returned invalid UTF-16 path: {e}\"),\n                )\n            })?;\n            return Ok(std::path::PathBuf::from(strip_windows_verbatim_prefix(\n                &path,\n            )));\n        }\n\n        buffer.resize(len + 1, 0);\n    }\n}\n\n#[cfg(windows)]\nfn strip_windows_verbatim_prefix(path: &str) -> String {\n    if let Some(rest) = path.strip_prefix(r\"\\\\?\\UNC\\\") {\n        format!(r\"\\\\{rest}\")\n    } else if let Some(rest) = path.strip_prefix(r\"\\\\?\\\") {","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-cache/src/cache_archive/create.rs#L646-L682","documentation":"On Windows, cache archive creation resolves a handle's true location with GetFinalPathNameByHandleW and then converts the returned UTF-16 buffer into a Rust String (create.rs:664 region). This error means the path Windows itself returned contained ill-formed UTF-16 (e.g. an unpaired surrogate), so String::from_utf16 failed. NTFS permits storing arbitrary UTF-16, so a file with such a name can make the OS hand back an unconvertible path.","triggerScenarios":"Hashing/archiving a file whose final (normalized, verbatim-stripped) path contains unpaired surrogate code units, during the realpath resolution loop in create.rs.","commonSituations":"Files created by buggy scripts or third-party installers that wrote invalid UTF-16 names Disk or MFT corruption after a crash Extremely rare on normal machines","solutions":["Locate the offending file (Explorer/PowerShell often render it as '?' or garbled) in the directory turbo was archiving and rename or delete it","Exclude the affected path from task inputs/outputs in turbo.json so it never enters the archive","Run `chkdsk` if you suspect filesystem corruption","Report it with the reproducing path so the guard can be improved"],"exampleFix":"// PowerShell: find files with surrogate-ish names under the output dir\nGet-ChildItem -Recurse -LiteralPath .\\dist | Where-Object { $_.Name -match '[\\uD800-\\uDFFF]' } | Rename-Item -NewName { $_.Name -replace '[\\uD800\\uDFFF]', '_' }","handlingStrategy":"try-catch","validationCode":"// Windows: pre-flight names you control before archiving\nfn utf16_ok(s: &str) -> bool { s.encode_utf16().count() > 0 } // Rust strs are valid; only OS-returned buffers can fail","typeGuard":null,"tryCatchPattern":"// cache_archive::create surfaces std::io::Error with kind()==InvalidData\nif let Err(e) = archive_create(...) {\n    if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains(\"invalid UTF-16\") {\n        // quarantine the offending path and continue with the rest\n    }\n}","preventionTips":["Keep generated filenames to ASCII/safe Unicode","Validate third-party tooling that writes files into build outputs"],"tags":["windows","cache","unicode","utf-16","path"],"backgroundTag":"invalid-filename-encoding","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}