{"id":"ac6c35ce6e271471","repo":"rust-lang/cargo","slug":"non-utf8-path","errorCode":null,"errorMessage":"non UTF8 path: {}","messagePattern":"non UTF8 path: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src/sources/registry/http_remote.rs","lineNumber":283,"sourceCode":"    }\n\n    async fn load(\n        &self,\n        _root: &Path,\n        path: &Path,\n        index_version: Option<&str>,\n    ) -> CargoResult<LoadResponse> {\n        // Ensure the config is loaded.\n        let Some(config) = self.config_opt().await? else {\n            return Ok(LoadResponse::NotFound);\n        };\n        self.inner()\n            .auth_required\n            .update(|v| v || config.auth_required);\n\n        let path = path\n            .to_str()\n            .ok_or_else(|| anyhow::anyhow!(\"non UTF8 path: {}\", path.display()))?;\n        self.sparse_fetch(path, index_version).await\n    }\n\n    async fn config(&self) -> CargoResult<Option<RegistryConfig>> {\n        Ok(Some(self.config().await?))\n    }\n\n    fn invalidate_cache(&self) {\n        // Actually updating the index is more or less a no-op for this implementation.\n        // All it does is ensure that a subsequent load will double-check files with the\n        // server rather than rely on a locally cached copy of the index files.\n        debug!(\"invalidated index cache\");\n        self.inner().fresh.borrow_mut().clear();\n        self.inner().requested_update.set(true);\n    }\n\n    fn set_quiet(&mut self, quiet: bool) {\n        self.inner().quiet.set(quiet);","sourceCodeStart":265,"sourceCodeEnd":301,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/sources/registry/http_remote.rs#L265-L301","documentation":"In `HttpRegistry::load` (src/sources/registry/http_remote.rs:281) Cargo converts the OS `Path` for an index entry into a `&str` via `path.to_str()`. On Windows (or any platform whose OS paths can be non-UTF-8) a path containing invalid Unicode yields `None` and this error. The sparse registry builds URLs by string concatenation, so a non-UTF-8 path can't be turned into a fetchable URL.","triggerScenarios":"A crate name or index path containing bytes that aren't valid UTF-8 reaching the sparse `load()` path. Cargo crate names are restricted to ASCII, so this is essentially unreachable through normal crates.io usage; it can only occur from an internally-constructed non-UTF-8 path or a corrupted in-memory state.","commonSituations":"Effectively never seen for crates.io (names are validated to `[A-Za-z0-9_-]`). Could surface in custom tooling that drives Cargo internals with non-UTF-8 paths, or on Windows with paths produced from non-UTF-16 sources.","solutions":["Ensure any crate names / paths you pass to Cargo are valid UTF-8 (they must be for crates.io anyway).","Treat as an internal invariant violation — file a cargo issue with the path bytes if you encounter it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before calling sparse load(), assert the path is UTF-8.\nfn ensure_utf8_path(path: &Path) -> CargoResult<&str> {\n    path.to_str().ok_or_else(|| anyhow::anyhow!(\"non UTF8 path: {}\", path.display()))\n}","typeGuard":"// Narrow a Path to a &str only when it is valid UTF-8.\npub fn utf8_path(p: &Path) -> Option<&str> { p.to_str() }","tryCatchPattern":null,"preventionTips":["Restrict crate names / index paths to ASCII (crates.io already enforces this).","Never construct non-UTF-8 paths when driving Cargo internals."],"tags":["cargo","registry","sparse","utf8","internal"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}