{"id":"307b2c7fb5db7da2","repo":"rust-lang/cargo","slug":"path-at-was-not-valid-utf-8","errorCode":null,"errorMessage":"path at `{}` was not valid utf-8","messagePattern":"path at `(.+?)` was not valid utf-8","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cargo-util/src/paths.rs","lineNumber":172,"sourceCode":"        .with_context(|| format!(\"failed to load metadata for path `{}`\", path.display()))\n}\n\n/// Returns metadata for a file without following symlinks.\n///\n/// Equivalent to [`std::fs::metadata`] with better error messages.\npub fn symlink_metadata<P: AsRef<Path>>(path: P) -> Result<Metadata> {\n    let path = path.as_ref();\n    std::fs::symlink_metadata(path)\n        .with_context(|| format!(\"failed to load metadata for path `{}`\", path.display()))\n}\n\n/// Reads a file to a string.\n///\n/// Equivalent to [`std::fs::read_to_string`] with better error messages.\npub fn read(path: &Path) -> Result<String> {\n    match String::from_utf8(read_bytes(path)?) {\n        Ok(s) => Ok(s),\n        Err(_) => anyhow::bail!(\"path at `{}` was not valid utf-8\", path.display()),\n    }\n}\n\n/// Reads a file into a bytes vector.\n///\n/// Equivalent to [`std::fs::read`] with better error messages.\npub fn read_bytes(path: &Path) -> Result<Vec<u8>> {\n    fs::read(path).with_context(|| format!(\"failed to read `{}`\", path.display()))\n}\n\n/// Writes a file to disk.\n///\n/// Equivalent to [`std::fs::write`] with better error messages.\npub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {\n    let path = path.as_ref();\n    fs::write(path, contents.as_ref())\n        .with_context(|| format!(\"failed to write `{}`\", path.display()))\n}","sourceCodeStart":154,"sourceCodeEnd":190,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/crates/cargo-util/src/paths.rs#L154-L190","documentation":"From paths::read (crates/cargo-util/src/paths.rs:169-174). It reads file bytes via read_bytes then converts to String with String::from_utf8; on failure it bails. Cargo expects UTF-8 for every text file it parses (manifests, config, lockfile, credential tokens), so non-UTF-8 content is treated as a hard error rather than lossy.","triggerScenarios":"Cargo reads a file (Cargo.toml, .cargo/config.toml, a registry token cache file, a credential) whose bytes are not valid UTF-8. For example a manifest saved in Latin-1/GBK/Shift-JIS, or a binary file mistakenly placed where text is expected.","commonSituations":"An editor or legacy toolchain saved Cargo.toml in a non-UTF-8 encoding. A credential file corrupted or overwritten with binary. Git autocrlf or transcoding mishandling on Windows with legacy locales. A path collision where Cargo opens the wrong (binary) file.","solutions":["Re-save the offending file as UTF-8 (most editors have an encoding command).","Identify which file failed from the `{}` path in the message, then inspect its encoding (`file -i <path>`).","If you genuinely need binary data, the calling code should use paths::read_bytes instead of paths::read.","Restore the file from version control if it was corrupted."],"exampleFix":"// before (caller expecting text but file is binary)\nlet text = cargo_util::paths::read(&path)?; // bails on non-utf8\n\n// after (handle binary gracefully)\nlet bytes = cargo_util::paths::read_bytes(&path)?;\nlet text = match std::str::from_utf8(&bytes) {\n    Ok(s) => s.to_owned(),\n    Err(_) => /* lossy fallback or user error */ String::from_utf8_lossy(&bytes).into_owned(),\n};","handlingStrategy":"validation","validationCode":"// Validate UTF-8 before assuming text\nfn try_read_text(path: &std::path::Path) -> Result<String, std::io::Error> {\n    let bytes = std::fs::read(path)?;\n    Ok(std::str::from_utf8(&bytes)\n        .map_err(|_| std::io::Error::new(std::io::ErrorKind::InvalidData, \"non-utf8\"))?\n        .to_owned())\n}\n\n// or simply use cargo_util::paths::read_bytes when binary is acceptable","typeGuard":"fn is_utf8_file(path: &std::path::Path) -> bool {\n    std::fs::read(path)\n        .ok()\n        .map(|b| std::str::from_utf8(&b).is_ok())\n        .unwrap_or(false)\n}","tryCatchPattern":"match cargo_util::paths::read(&path) {\n    Ok(s) => s,\n    Err(_) => {\n        let bytes = cargo_util::paths::read_bytes(&path)?;\n        String::from_utf8_lossy(&bytes).into_owned()\n    }\n}","preventionTips":["Always save manifests/config as UTF-8.","In editors, set the default encoding to UTF-8.","When unsure if a file is text, use read_bytes and validate before converting."],"tags":["io","utf-8","encoding","files","cargo-util"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}