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

  1. Set `registries.crates-io.protocol` to either `"sparse"` or `"git"` in your config file, matching Cargo's accepted vocabulary.
  2. Remove the `registries.crates-io.protocol` key entirely to fall back to the default (sparse) behavior.
  3. 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

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


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)