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

  1. Set `registries.crates-io.protocol = "sparse"` (the modern default) or `"git"` in your `.cargo/config.toml`.
  2. Remove the `registries.crates-io.protocol` line entirely — `None` defaults to sparse (line 290).
  3. 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

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


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/1a64f0fef4bd106d.json. Report an issue: GitHub.