rust-lang/cargo · error · anyhow::Error
unsupported registry protocol `{unknown}` (defined in {})
Error message
unsupported registry protocol `{unknown}` (defined in {}) What it means
Raised by `SourceId::crates_io_is_sparse` (src/workspace/source_id.rs:281) when the `registries.crates-io.protocol` config value is set to something other than the two accepted strings "sparse" or "git". Cargo only supports those two protocols for the crates.io index, so any third value (typos like "spars", "http", "sparse-http") causes an immediate `anyhow::bail!` that also reports the config `definition` (the file/line where the bad value was set).
Source
Thrown at src/workspace/source_id.rs:286
/// sparse HTTP index if allowed.
pub fn crates_io_maybe_sparse_http(gctx: &GlobalContext) -> CargoResult<SourceId> {
if Self::crates_io_is_sparse(gctx)? {
gctx.check_registry_index_not_set()?;
let url = CRATES_IO_HTTP_INDEX.into_url().unwrap();
let key = KeyOf::Registry(CRATES_IO_REGISTRY.into());
SourceId::new(SourceKind::SparseRegistry, url, Some(key))
} else {
Self::crates_io(gctx)
}
}
/// Returns whether to access crates.io over the sparse protocol.
pub fn crates_io_is_sparse(gctx: &GlobalContext) -> CargoResult<bool> {
let proto: Option<context::Value<String>> = gctx.get("registries.crates-io.protocol")?;
let is_sparse = match proto.as_ref().map(|v| v.val.as_str()) {
Some("sparse") => true,
Some("git") => false,
Some(unknown) => anyhow::bail!(
"unsupported registry protocol `{unknown}` (defined in {})",
proto.as_ref().unwrap().definition
),
None => true,
};
Ok(is_sparse)
}
/// Gets the `SourceId` associated with given name of the remote registry.
pub fn alt_registry(gctx: &GlobalContext, key: &str) -> CargoResult<SourceId> {
if key == CRATES_IO_REGISTRY {
return Self::crates_io(gctx);
}
let url = gctx.get_registry_index(key)?;
Self::for_alt_registry(&url, key)
}
/// Gets this source URL.View on GitHub (pinned to 0e07a15537)
Solutions
- Set `registries.crates-io.protocol = "sparse"` (the modern default) or `"git"` in your `.cargo/config.toml`.
- Remove the `registries.crates-io.protocol` line entirely — `None` defaults to sparse (line 290).
- Check every config layer (`~/.cargo/config.toml`, repo `.cargo/config.toml`, `$CARGO_HOME/config.toml`) since the error names the offending `definition`.
Example fix
# before [registries.crates-io] protocol = "spars" # after [registries.crates-io] protocol = "sparse"
Defensive patterns
Strategy: validation
Validate before calling
fn valid_protocol(v: &str) -> bool { matches!(v, "sparse" | "git") }
// before writing config: assert valid_protocol(value) Type guard
const isProtocol = (v: unknown): v is "sparse" | "git" => v === "sparse" || v === "git";
Prevention
- Only ever set `registries.crates-io.protocol` to "sparse" or "git".
- Omit the key to get the safe default (sparse).
- Lint config files for this key before committing.
When it happens
Trigger: Setting `registries.crates-io.protocol` in `.cargo/config.toml` or `~/.cargo/config.toml` to a value that is neither `"sparse"` nor `"git"`. The branch `Some(unknown) =>` in the match at line 286 fires for any other string.
Common situations: Typing `protocol = "spars"` or `protocol = "sparse"` mis-capitalized; copying an outdated config snippet that used `"http"` or `"https"`; a CI image baking a wrong protocol value; cargo version downgrade where the value was once different.
Related errors
- config.json not found
- sparse registry url must end in a slash `/`: {url}
- 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/1a64f0fef4bd106d.json.
Report an issue: GitHub.