cross-rs/cross · error

invalid toolchain

Error message

invalid toolchain `{s}`

What it means

`Toolchain::from_str` parses rustup-style toolchain names like `stable-2023-01-10-x86_64-unknown-linux-gnu`. When the optional date component is present but not three 2-digit-separated groups of digits (Y-M-D), parsing bails with `invalid toolchain \`{s}\``. It guards against malformed toolchain identifiers before constructing the struct.

Solutions

  1. Use the canonical rustup format: `channel[-YYYY-MM-DD][-host-triple]`, e.g. `nightly-2023-05-01-x86_64-unknown-linux-gnu`.
  2. Remove the date entirely (`nightly`) or use the full official name from `rustup toolchain list`.
  3. Check your rust-toolchain.toml / RUSTUP_TOOLCHAIN value for stray characters or double dashes.
  4. Validate the string with a regex like `^(stable|beta|nightly|\d+\.\d+(\.\d+)?)(-\d{4}-\d{2}-\d{2})?(-[a-z0-9_-]+)?$` before passing it in.

Example fix

// before
RUSTUP_TOOLCHAIN=nightly-20230501-x86_64-unknown-linux-gnu
// after
RUSTUP_TOOLCHAIN=nightly-2023-05-01-x86_64-unknown-linux-gnu
Defensive patterns

Strategy: validation

Validate before calling

const TOOLCHAIN_RE: &str = r"^[A-Za-z0-9._+]+(-\d{4}-\d{2}-\d{2})?(-[a-z0-9_-]+)?$";
fn valid_toolchain(s: &str) -> bool { regex::Regex::new(TOOLCHAIN_RE).unwrap().is_match(s) }

Try / catch

let toolchain = Toolchain::from_str(input)
    .map_err(|e| format!("Bad toolchain '{input}': use channel[-YYYY-MM-DD][-triple], e.g. nightly-2023-05-01"))?;

Prevention

When it happens

Trigger: Passing a toolchain string whose date part is malformed, e.g. `stable-20230101-x86_64-unknown-linux-gnu`, `nightly-2023-1-10-...`, or extra/missing dashes so `splitn(4,'-')` does not yield three digit-only parts.

Common situations: Hand-edited rust-toolchain files; copy-pasted toolchain names with wrong dash grouping; scripts that format dates as YYYYMMDD instead of YYYY-MM-DD; toolchain names containing extra hyphens from target triples interacting with splitn.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of cross-rs/cross@8c1a8aa4b6 (2026-09-13). Data as JSON: /api/errors/8233568c6faa3869. Report an issue: GitHub.

Appendix: source

Thrown at src/rustc.rs:324

}

impl std::str::FromStr for Toolchain {
    type Err = eyre::Report;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        fn dig(s: &str) -> bool {
            s.chars().all(|c: char| c.is_ascii_digit())
        }
        if let Some((channel, parts)) = s.split_once('-') {
            if parts.starts_with(|c: char| c.is_ascii_digit()) {
                // a date, YYYY-MM-DD
                let mut split = parts.splitn(4, '-');
                let ymd = [split.next(), split.next(), split.next()];
                let ymd = match ymd {
                    [Some(y), Some(m), Some(d)] if dig(y) && dig(m) && dig(d) => {
                        format!("{y}-{m}-{d}")
                    }
                    _ => eyre::bail!("invalid toolchain `{s}`"),
                };
                Ok(Toolchain {
                    channel: channel.to_owned(),
                    date: Some(ymd),
                    host: split.next().map(|s| s.into()),
                    is_custom: false,
                    full: s.to_owned(),
                })
            } else {
                // channel-host
                Ok(Toolchain {
                    channel: channel.to_owned(),
                    date: None,
                    host: Some(parts.into()),
                    is_custom: false,
                    full: s.to_owned(),
                })
            }

View on GitHub (pinned to 8c1a8aa4b6)