rust-lang/cargo · error · anyhow::Error
sparse registry url must end in a slash `/`: {url}
Error message
sparse registry url must end in a slash `/`: {url} What it means
When constructing an `HttpBackend` for a sparse registry (src/sources/registry/http_remote.rs:390), Cargo requires the index URL to end with `/` because it builds crate index URLs by string concatenation (`url + relative_path`). A URL without a trailing slash would silently produce wrong paths, so it bails hard.
Source
Thrown at src/sources/registry/http_remote.rs:393
login_url: RefCell<Option<Url>>,
/// Headers received with an HTTP 401.
auth_error_headers: RefCell<Vec<String>>,
/// Disables status messages.
quiet: Cell<bool>,
}
impl<'gctx> HttpBackend<'gctx> {
pub fn new(
source_id: SourceId,
gctx: &'gctx GlobalContext,
name: &str,
) -> CargoResult<HttpBackend<'gctx>> {
let url = source_id.url().as_str();
// Ensure the url ends with a slash so we can concatenate paths.
if !url.ends_with('/') {
anyhow::bail!("sparse registry url must end in a slash `/`: {url}")
}
assert!(source_id.is_sparse());
let url = url
.strip_prefix("sparse+")
.expect("sparse registry needs sparse+ prefix")
.into_url()
.expect("a url with the sparse+ stripped should still be valid");
let index_cache_path = gctx.registry_index_path().join(name);
Ok(HttpBackend {
index_cache_path: index_cache_path.clone(),
crate_cache_path: gctx.registry_cache_path().join(name),
source_id,
gctx,
url,
progress: RefCell::new(Some(Progress::with_style(
"Fetch",
ProgressStyle::Indeterminate,View on GitHub (pinned to 0e07a15537)
Solutions
- Add a trailing `/` to the index URL everywhere it's configured.
- Search all config sources (`.cargo/config.toml`, `Cargo.toml`, `~/.cargo/config.toml`, `CARGO_REGISTRIES_<NAME>_INDEX` env) for the offending URL.
Example fix
# before [registries.my-reg] index = "sparse+https://index.crates.io" # -> sparse registry url must end in a slash # after [registries.my-reg] index = "sparse+https://index.crates.io/"
Defensive patterns
Strategy: validation
Validate before calling
// Validate the trailing slash when constructing a sparse registry SourceId.
fn ensure_trailing_slash(url: &str) -> CargoResult<()> {
if !url.ends_with('/') {
anyhow::bail!("sparse registry url must end in a slash `/`: {url}");
}
Ok(())
} Type guard
pub fn is_well_formed_sparse_url(url: &str) -> bool {
url.starts_with("sparse+") && url.ends_with('/')
} Prevention
- Always end sparse index URLs with `/`.
- Centralize registry URL validation in config-loading code so misconfiguration fails early.
When it happens
Trigger: Configuring a registry with `index = "sparse+https://example.com/index"` (no trailing slash); passing a bare URL to `cargo --index sparse+https://...`. Triggered at `HttpBackend::new` during source creation.
Common situations: Copy-pasting a sparse URL without the trailing slash in `.cargo/config.toml`, `Cargo.toml` `[registries]`, or a `--index` CLI argument; migrating from the git protocol (which doesn't require a trailing slash) to sparse.
Related errors
- config.json not found
- non UTF8 path: {}
- local registry path is not a directory: {}
- local registry index path is not a directory: {}
- multiple registries are configured with the same index url '
AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06).
Data as JSON: /data/errors/621363497c78db97.json.
Report an issue: GitHub.