rust-lang/cargo · error · anyhow::Error

unknown vcs specification

Error message

unknown vcs specification: `{}`

What it means

This error is raised when a `VersionControl` value cannot be parsed from a string via its `FromStr` implementation (used during config deserialization). The string must exactly match one of the supported VCS names: `git`, `hg`, `pijul`, `fossil`, or `none`. Any other value (including typos, capitalization differences, or empty strings) aborts with `unknown vcs specification: \`<input>\``.

Solutions

  1. Open the config file and change the `vcs` value to one of exactly: `git`, `hg`, `pijul`, `fossil`, or `none` (lowercase, no whitespace).
  2. If a template/variable was supposed to be substituted (message shows a literal `{}`), fix the templating/substitution step so a real VCS name is written.
  3. Check the docs for the config schema to confirm which VCS aliases are supported; there are none beyond the five listed — e.g. `mercurial` is not accepted, use `hg`.
  4. If you need a new VCS supported, this is upstream code (src/context/schema.rs `from_str`); file/patch the library to add the match arm.

Example fix

// before (config)
vcs = "mercurial"

// after (config)
vcs = "hg"
Defensive patterns

Strategy: validation

Validate before calling

const VALID_VCS: &[&str] = &["git", "hg", "pijul", "fossil", "none"];
fn is_valid_vcs(s: &str) -> bool {
    VALID_VCS.contains(&s.trim())
}
// before deserializing config:
assert!(is_valid_vcs(cfg.vcs.as_str()), "unsupported vcs: {}", cfg.vcs);

Type guard

fn is_known_vcs(s: &str) -> Option<VersionControl> {
    match s.trim() {
        "git" => Some(VersionControl::Git),
        "hg" => Some(VersionControl::Hg),
        "pijul" => Some(VersionControl::Pijul),
        "fossil" => Some(VersionControl::Fossil),
        "none" => Some(VersionControl::NoVcs),
        _ => None,
    }
}

Try / catch

match VersionControl::from_str(raw) {
    Ok(vcs) => /* proceed */,
    Err(e) => eprintln!("config error: {e}; expected one of git, hg, pijul, fossil, none"),
}

Prevention

When it happens

Trigger: Deserializing a config (e.g. cargo/alternative-registry style config) whose `vcs` key (or equivalent field of type `VersionControl`) contains a value other than the five recognized strings, e.g. `vcs = "Git"` (capitalized), `vcs = "mercurial"`, or a variable left unexpanded like the literal `{}` shown in the message when formatting substitutes the offending input.

Common situations: Typing `vcs = "git"` with stray whitespace or wrong case; using a full VCS name like `mercurial` or `subversion` instead of `hg`; templated config where a placeholder was not substituted (message shows a literal `{}`); migrating configs from tools that accept different VCS names.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of rust-lang/cargo@98a09e7e7d (2026-09-16). Data as JSON: /api/errors/7cfabaa870875f33. Report an issue: GitHub.

Appendix: source

Thrown at src/context/schema.rs:114

            VersionControl::Hg => "hg",
            VersionControl::Pijul => "pijul",
            VersionControl::Fossil => "fossil",
            VersionControl::NoVcs => "none",
        }
    }
}

impl FromStr for VersionControl {
    type Err = anyhow::Error;

    fn from_str(s: &str) -> Result<Self, anyhow::Error> {
        match s {
            "git" => Ok(VersionControl::Git),
            "hg" => Ok(VersionControl::Hg),
            "pijul" => Ok(VersionControl::Pijul),
            "fossil" => Ok(VersionControl::Fossil),
            "none" => Ok(VersionControl::NoVcs),
            other => anyhow::bail!("unknown vcs specification: `{}`", other),
        }
    }
}

impl<'de> de::Deserialize<'de> for VersionControl {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: de::Deserializer<'de>,
    {
        let s = String::deserialize(deserializer)?;
        FromStr::from_str(&s).map_err(de::Error::custom)
    }
}

/// Definition of a source in a config file.
#[derive(Debug, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct SourceConfigDef {

View on GitHub (pinned to 98a09e7e7d)