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
- 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
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
- 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.
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
- attributes not supported on queries
- attributes must be outer attributes (`///`), not inner attri
- {:?} shouldn't exist here
- duplicate modifier
- unknown query modifier
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/5e456cae6814912f.json.
Report an issue: GitHub.