rust-lang/cargo · error
non UTF8 path
Error message
non UTF8 path: {} What it means
While loading a crate's metadata from a sparse (HTTP) registry, Cargo converts the requested `path` to a `&str` via `Path::to_str()`. If the path contains non-UTF-8 bytes (OsStr not representable as UTF-8), conversion fails. Crate names in the index are always ASCII, so this indicates a malformed or non-UTF-8 path was passed to the load routine.
Solutions
- Ensure any path passed to registry load routines is valid UTF-8 (sanitize/normalize crate names before lookup).
- If calling Cargo as a library, validate `path.to_str().is_some()` before invoking load.
- Report a Cargo bug if this fires during normal CLI usage (crate names should be ASCII).
Example fix
// before: pass arbitrary OsStr path
let resp = backend.load(root, non_utf8_path, None).await?;
// after: validate UTF-8 first
let path_str = path.to_str()
.ok_or_else(|| anyhow!("non UTF8 path"))?;
let resp = backend.load(root, std::path::Path::new(path_str), None).await?; Defensive patterns
Strategy: type-guard
Validate before calling
fn require_utf8_path(path: &Path) -> Result<&str, anyhow::Error> {
path.to_str().ok_or_else(|| anyhow::anyhow!("path is not UTF-8: {}", path.display()))
} Type guard
fn is_utf8_path(path: &std::path::Path) -> bool { path.to_str().is_some() } Try / catch
let path_str = match path.to_str() {
Some(s) => s,
None => { tracing::warn!("skipping non-UTF-8 path"); return Ok(LoadResponse::NotFound); }
}; Prevention
- Sanitize crate names to ASCII before lookup.
- When calling Cargo as a library, never pass arbitrary OsStr paths.
- Report a bug if this surfaces during normal CLI usage.
When it happens
Trigger: `load()` is called with a `&Path` whose OsStr is not valid UTF-8; `.to_str()` returns `None`. Practically unreachable from normal Cargo flows (crate names are validated ASCII) but could be hit by programmatic callers passing arbitrary paths or on platforms with non-UTF-8 path encoding.
Common situations: Programmatic use of Cargo as a library passing non-UTF-8 paths; filesystem locale producing non-UTF-8 path bytes; corrupted in-memory path construction.
Related errors
- sparse registry url must end in a slash `/
- config.json not found
- ` ` resolved to non-UTF value (` `)
- unsupported registry protocol
- cache expected 4 bytes for index schema version
AI-assisted analysis of rust-lang/cargo@eb98b54bc9 (2026-08-11).
Data as JSON: /api/errors/ac6c35ce6e271471.
Report an issue: GitHub.
Appendix: source
Thrown at src/sources/registry/http_remote.rs:283
}
async fn load(
&self,
_root: &Path,
path: &Path,
index_version: Option<&str>,
) -> CargoResult<LoadResponse> {
// Ensure the config is loaded.
let Some(config) = self.config_opt().await? else {
return Ok(LoadResponse::NotFound);
};
self.inner()
.auth_required
.update(|v| v || config.auth_required);
let path = path
.to_str()
.ok_or_else(|| anyhow::anyhow!("non UTF8 path: {}", path.display()))?;
self.sparse_fetch(path, index_version).await
}
async fn config(&self) -> CargoResult<Option<RegistryConfig>> {
Ok(Some(self.config().await?))
}
fn invalidate_cache(&self) {
// Actually updating the index is more or less a no-op for this implementation.
// All it does is ensure that a subsequent load will double-check files with the
// server rather than rely on a locally cached copy of the index files.
debug!("invalidated index cache");
self.inner().fresh.borrow_mut().clear();
self.inner().requested_update.set(true);
}
fn set_quiet(&mut self, quiet: bool) {
self.inner().quiet.set(quiet);View on GitHub (pinned to eb98b54bc9)