rust-lang/rust · error · syn::Error

{env_var} env var: {err}

Error message

{env_var} env var: {err}

What it means

Compile-time error produced by the current_version proc-macro (the rustc_version attribute) when it cannot read or parse the CFG_RELEASE environment variable. It uses proc_macro::tracked::env_var to fetch CFG_RELEASE and RustcVersion::parse_str to split it into major.minor.patch; either step failing yields this syn::Error rendered at the call site. Because CFG_RELEASE is normally set by rustbuild/bootstrap, this error means the macro was expanded outside the proper rustc build environment.

Source

Thrown at compiler/rustc_macros/src/current_version.rs:12

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::quote;

pub(crate) fn current_version(_input: TokenStream) -> TokenStream {
    let env_var = "CFG_RELEASE";
    TokenStream::from(match RustcVersion::parse_cfg_release(env_var) {
        Ok(RustcVersion { major, minor, patch }) => quote!(
            // The produced literal has type `rustc_session::RustcVersion`.
            Self { major: #major, minor: #minor, patch: #patch }
        ),
        Err(err) => syn::Error::new(Span::call_site(), format!("{env_var} env var: {err}"))
            .into_compile_error(),
    })
}

struct RustcVersion {
    major: u16,
    minor: u16,
    patch: u16,
}

impl RustcVersion {
    fn parse_cfg_release(env_var: &str) -> Result<Self, Box<dyn std::error::Error>> {
        let value = proc_macro::tracked::env_var(env_var)?;

        Self::parse_str(&value)
            .ok_or_else(|| format!("failed to parse rustc version: {:?}", value).into())
    }

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Build rustc components through ./x.py rather than bare cargo, so bootstrap sets CFG_RELEASE
  2. If building manually, export CFG_RELEASE with a numeric M.N.P value (e.g. CFG_RELEASE=1.89.0)
  3. Audit shell rc files, Makefiles, and CI for anything unsetting or overriding CFG_RELEASE
  4. Ensure the value is parseable: digits and dots, optional -suffix; no bare words

Example fix

# before (bare cargo, no env)
cargo build -p rustc_session
# after
./x.py build compiler/rustc
# or
CFG_RELEASE=1.89.0-dev cargo build -p rustc_session
Defensive patterns

Strategy: validation

Validate before calling

// Error reading/parsing an env var at rustc build time (current_version.rs).
// Validate the env var before the build that invokes rustc_macros:
use std::env;

fn require_env_var(name: &str) -> Result<String, String> {
    let v = env::var(name).map_err(|e| format!("{} env var: {}", name, e))?;
    if v.trim().is_empty() {
        return Err(format!("{} env var: empty value", name));
    }
    // If it's expected to be semver-ish, validate:
    if name == "RUSTC_RELEASE_NUM" || name == "CFG_RELEASE" {
        if !v.chars().next().map(|c| c.is_ascii_digit()).unwrap_or(false) {
            return Err(format!("{} env var: not a version-like value: {}", name, v));
        }
    }
    Ok(v)
}

// in build.rs, before any codegen that depends on current_version:
// let _ = require_env("CFG_RELEASE")?;

Type guard

fn env_var_kind(name: &str) -> &'static str {
    match name {
        "CFG_RELEASE" | "RUSTC_RELEASE_NUM" | "CFG_VERGEN_SHA" => "version",
        "CFG_VERSION" => "version_string",
        _ => "opaque",
    }
}

fn is_expected_env_value(name: &str, v: &str) -> bool {
    match env_var_kind(name) {
        "version" => v.split('.').all(|p| p.bytes().all(|b| b.is_ascii_digit())) && !v.is_empty(),
        "version_string" => !v.trim().is_empty(),
        _ => true,
    }
}

Try / catch

// This fires inside rustc_macros (proc-macro / build-script context).
// Wrap the build that depends on it and produce a clear failure:
fn build_with_current_version() -> Result<(), String> {
    for var in ["CFG_RELEASE", "CFG_VERSION", "CFG_VERGEN_SHA"] {
        match std::env::var(var) {
            Ok(v) if is_expected_env_value(var, &v) => {},
            Ok(v) => return Err(format!("{} env var: malformed value {:?}", var, v)),
            Err(e) => return Err(format!("{} env var: {}", var, e)),
        }
    }
    // proceed with the rustc build
    Ok(())
}

Prevention

When it happens

Trigger: The macro expands (i.e. some item annotated with #[rustc_version] or whatever current_version drives) and either proc_macro::tracked::env_var("CFG_RELEASE") returns an Err (env var not set / not tracked) or parse_str returns None (value does not match M.N[.P] after stripping a -suffix). syn::Error::new at Span::call_site() surfaces "{env_var} env var: {err}".

Common situations: Running cargo build directly inside a rustc_* subcrate instead of via ./x.py; CFG_RELEASE missing because bootstrap was bypassed; CFG_RELEASE set to a malformed string like "nightly" without a numeric prefix; env var shadowed/emptied in a custom build script.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/5e456cae6814912f.json. Report an issue: GitHub.