valeriansaliou/sonic · error · panic

env_var: variable '{key}' is not set

Error message

env_var: variable '{key}' is not set

What it means

Sonic's config deserializer supports ${env.VAR} interpolation in the TOML file. get_env_var panics via std::env::var when the referenced environment variable is not set, aborting config parsing. Helpers affected: str, opt_str, socket_addr, path_buf.

Source

Thrown at core/src/util/serde.rs:118

    fn is_env_var(value: &str) -> bool {
        Regex::new(r"^\$\{env\.\w+\}$")
            .expect("env_var: regex is invalid")
            .is_match(value)
    }

    fn get_env_var(wrapped_key: &str) -> String {
        let key: String = String::from(wrapped_key)
            .drain(6..(wrapped_key.len() - 1))
            .collect();

        // NOTE: While we could deprecate the `${env.*}` syntax now that Sonic has
        //   first-class support for environment variables, it would force people
        //   to use the Sonic naming convention and potentially duplicate some
        //   variables. For better UX, let’s keep it that way. It doesn’t require
        //   dependencies nor bloat the code so it’s acceptable.

        std::env::var(&key).unwrap_or_else(|_| panic!("env_var: variable '{key}' is not set"))
    }

    #[cfg(test)]
    mod tests {
        use super::*;

        #[test]
        fn it_checks_environment_variable_patterns() {
            assert!(is_env_var("${env.XXX}"));
            assert!(!is_env_var("${env.XXX"));
            assert!(!is_env_var("${env.XXX}a"));
            assert!(!is_env_var("a${env.XXX}"));
            assert!(!is_env_var("{env.XXX}"));
            assert!(!is_env_var("$env.XXX}"));
            assert!(!is_env_var("${envXXX}"));
            assert!(!is_env_var("${.XXX}"));
            assert!(!is_env_var("${XXX}"));
        }

View on GitHub (pinned to e6a72da6a5)

Solutions

  1. Export the missing variable before starting the server (e.g. export CHANNEL_PORT=1491)
  2. Fix the variable name in the config to match the environment
  3. Pass the variable through your deployment (docker run -e / k8s env)
  4. Replace the ${env.*} reference with a literal value

Example fix

// shell
// before
./sonic  # config has ${env.SONIC_PASSWORD}, not set
// after
export SONIC_PASSWORD=secret && ./sonic
Defensive patterns

Strategy: validation

Validate before calling

// extract every ${env.NAME} from the config and fail fast
for key in extract_env_refs(config_text) {
    assert!(
        std::env::var(&key).is_ok(),
        "missing environment variable: {}",
        key
    );
}

Try / catch

// if you parse config yourself
match std::env::var("CHANNEL_PORT") {
    Ok(v) => v,
    Err(std::env::VarError::NotPresent) => return Err(format!("env var CHANNEL_PORT not set")),
    Err(e) => return Err(e.to_string().into()),
}

Prevention

When it happens

Trigger: A config file value like channel = "${env.CHANNEL_PORT}" where CHANNEL_PORT is absent from the process environment when the server starts.

Common situations: Deploying without sourcing an .env file; typos in the variable name; container/orchestrator not injecting the variable; variable defined for the shell but not the service's environment.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of valeriansaliou/sonic@e6a72da6a5 (2026-09-01). Data as JSON: /api/errors/96a1d7e05770b70b. Report an issue: GitHub.