{"id":"5e456cae6814912f","repo":"rust-lang/rust","slug":"env-var-env-var-err","errorCode":null,"errorMessage":"{env_var} env var: {err}","messagePattern":"(.+?) env var: (.+?)","errorType":"validation","errorClass":"syn::Error","httpStatus":null,"severity":"error","filePath":"compiler/rustc_macros/src/current_version.rs","lineNumber":12,"sourceCode":"use proc_macro::TokenStream;\nuse proc_macro2::Span;\nuse quote::quote;\n\npub(crate) fn current_version(_input: TokenStream) -> TokenStream {\n    let env_var = \"CFG_RELEASE\";\n    TokenStream::from(match RustcVersion::parse_cfg_release(env_var) {\n        Ok(RustcVersion { major, minor, patch }) => quote!(\n            // The produced literal has type `rustc_session::RustcVersion`.\n            Self { major: #major, minor: #minor, patch: #patch }\n        ),\n        Err(err) => syn::Error::new(Span::call_site(), format!(\"{env_var} env var: {err}\"))\n            .into_compile_error(),\n    })\n}\n\nstruct RustcVersion {\n    major: u16,\n    minor: u16,\n    patch: u16,\n}\n\nimpl RustcVersion {\n    fn parse_cfg_release(env_var: &str) -> Result<Self, Box<dyn std::error::Error>> {\n        let value = proc_macro::tracked::env_var(env_var)?;\n\n        Self::parse_str(&value)\n            .ok_or_else(|| format!(\"failed to parse rustc version: {:?}\", value).into())\n    }\n","sourceCodeStart":1,"sourceCodeEnd":30,"githubUrl":"https://github.com/rust-lang/rust/blob/22057b88b091743bc0fd8d592a9264f0a6951403/compiler/rustc_macros/src/current_version.rs#L1-L30","documentation":"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.","triggerScenarios":"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}\".","commonSituations":"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.","solutions":["Build rustc components through ./x.py rather than bare cargo, so bootstrap sets CFG_RELEASE","If building manually, export CFG_RELEASE with a numeric M.N.P value (e.g. CFG_RELEASE=1.89.0)","Audit shell rc files, Makefiles, and CI for anything unsetting or overriding CFG_RELEASE","Ensure the value is parseable: digits and dots, optional -suffix; no bare words"],"exampleFix":"# before (bare cargo, no env)\ncargo build -p rustc_session\n# after\n./x.py build compiler/rustc\n# or\nCFG_RELEASE=1.89.0-dev cargo build -p rustc_session","handlingStrategy":"validation","validationCode":"// Error reading/parsing an env var at rustc build time (current_version.rs).\n// Validate the env var before the build that invokes rustc_macros:\nuse std::env;\n\nfn require_env_var(name: &str) -> Result<String, String> {\n    let v = env::var(name).map_err(|e| format!(\"{} env var: {}\", name, e))?;\n    if v.trim().is_empty() {\n        return Err(format!(\"{} env var: empty value\", name));\n    }\n    // If it's expected to be semver-ish, validate:\n    if name == \"RUSTC_RELEASE_NUM\" || name == \"CFG_RELEASE\" {\n        if !v.chars().next().map(|c| c.is_ascii_digit()).unwrap_or(false) {\n            return Err(format!(\"{} env var: not a version-like value: {}\", name, v));\n        }\n    }\n    Ok(v)\n}\n\n// in build.rs, before any codegen that depends on current_version:\n// let _ = require_env(\"CFG_RELEASE\")?;","typeGuard":"fn env_var_kind(name: &str) -> &'static str {\n    match name {\n        \"CFG_RELEASE\" | \"RUSTC_RELEASE_NUM\" | \"CFG_VERGEN_SHA\" => \"version\",\n        \"CFG_VERSION\" => \"version_string\",\n        _ => \"opaque\",\n    }\n}\n\nfn is_expected_env_value(name: &str, v: &str) -> bool {\n    match env_var_kind(name) {\n        \"version\" => v.split('.').all(|p| p.bytes().all(|b| b.is_ascii_digit())) && !v.is_empty(),\n        \"version_string\" => !v.trim().is_empty(),\n        _ => true,\n    }\n}","tryCatchPattern":"// This fires inside rustc_macros (proc-macro / build-script context).\n// Wrap the build that depends on it and produce a clear failure:\nfn build_with_current_version() -> Result<(), String> {\n    for var in [\"CFG_RELEASE\", \"CFG_VERSION\", \"CFG_VERGEN_SHA\"] {\n        match std::env::var(var) {\n            Ok(v) if is_expected_env_value(var, &v) => {},\n            Ok(v) => return Err(format!(\"{} env var: malformed value {:?}\", var, v)),\n            Err(e) => return Err(format!(\"{} env var: {}\", var, e)),\n        }\n    }\n    // proceed with the rustc build\n    Ok(())\n}","preventionTips":["Set every env var that rustc_macros/current_version.rs reads (CFG_RELEASE, CFG_VERSION, CFG_VERGEN_*) explicitly in your build environment.","Do not rely on inherit-only: emit them in CI matrix config and verify with a pre-build step.","For reproducible builds, pin these values to known constants rather than reading git at build time.","In build.rs, read them once and pass down, instead of each macro re-reading env.","Fail the build with a precise message when a required var is missing rather than letting the macro panic."],"tags":["proc-macro","build-env","bootstrap","rustc-internal"],"analyzedSha":"22057b88b091743bc0fd8d592a9264f0a6951403","analyzedAt":"2026-08-03T08:09:25.915Z","schemaVersion":2}