rust-lang/cargo · error
unsupported registry protocol
Error message
unsupported registry protocol `{unknown}` (defined in {}) What it means
Cargo validates the `registries.crates-io.protocol` configuration key when deciding how to access crates.io. The matcher accepts only three outcomes: the literal string `sparse` (returns true), the literal string `git` (returns false), or an unset/None value (defaults to sparse). Any other string value reaches the `Some(unknown)` arm and is rejected. The error message interpolates both the offending value and the config definition location so the user can find where it was set.
Solutions
- Set `registries.crates-io.protocol` to either `"sparse"` or `"git"` in your config file, matching Cargo's accepted vocabulary.
- Remove the `registries.crates-io.protocol` key entirely to fall back to the default (sparse) behavior.
- Inspect every config definition site printed in the error message (`defined in {}`) to find which file layer supplies the bad value, including `~/.cargo/config.toml`, project `.cargo/config.toml`, and env config overrides.
Example fix
// before (in .cargo/config.toml) [registries.crates-io] protocol = "sparse-registry" // after [registries.crates-io] protocol = "sparse"
Defensive patterns
Strategy: validation
Validate before calling
fn valid_protocol(p: &str) -> bool { matches!(p, "sparse" | "git") }
// before reading config, validate the intended value
let proto: String = /* user/intended value */;
assert!(valid_protocol(&proto), "protocol must be 'sparse' or 'git'"); Prevention
- Treat `registries.crates-io.protocol` as an enum of two literals; validate at config-authoring time.
- Keep a single source of truth for the value and lint it in CI.
- When upgrading Cargo, diff your `.cargo/config.toml` against the version's accepted keys.
When it happens
Trigger: Calling `SourceId::crates_io_is_sparse(gctx)` after Cargo reads `registries.crates-io.protocol` from config. Triggered when the resolved `context::Value<String>` is `Some(s)` where `s` is neither `"sparse"` nor `"git"` (e.g. `"http"`, `"sparse-registry"`, `"https"`, or a typo).
Common situations: Typos in `.cargo/config.toml` (e.g. `protocol = "sparse-registry"` instead of `"sparse"`), using values valid in a newer/older Cargo on an incompatible version, copying config snippets from outdated documentation, or setting the key via environment-driven config layers to an unsupported token.
Related errors
- config.json not found
- found build scripts with duplicate file stems, but all…
- found duplicate name , but all targets must have a unique…
- found patches and a path override
- invalid `package.build` file name
AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-08-11).
Data as JSON: /api/errors/1a64f0fef4bd106d.
Report an issue: GitHub.
Appendix: source
Thrown at src/workspace/source_id.rs:287
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 98a09e7e7d)