dbt-labs/dbt-core · error · minijinja::Error (InvalidOperation)

Environment variables (starting with {DBT_INTERNAL_ENV_VAR_P

Error message

Environment variables (starting with {DBT_INTERNAL_ENV_VAR_PREFIX}) cannot be accessed here

What it means

Environment variables whose names start with `_DBT` are reserved for dbt's internal machinery and are blocked from Jinja `env_var` access. This prevents user code from reading or depending on internal state variables, whose names and semantics may change between dbt versions. The check runs unconditionally, before any environment lookup or default fallback.

Source

Thrown at crates/dbt-jinja-vars/src/env_var.rs:64

    if let Some(value) = overrides_fn.and_then(|f| f(var)) {
        return Ok(value);
    }

    let is_secret = var.starts_with(SECRET_ENV_VAR_PREFIX);
    if is_secret && !placeholder_on_secret_access {
        let err = Error::new(
            ErrorKind::InvalidOperation,
            format!(
                "Secret environment variables (starting with {SECRET_ENV_VAR_PREFIX}) \
                cannot be accessed here"
            ),
        );
        return Err(err);
    }
    let is_internal = var.starts_with(DBT_INTERNAL_ENV_VAR_PREFIX);
    if is_internal {
        let err = Error::new(
            ErrorKind::InvalidOperation,
            format!(
                "Environment variables (starting with {DBT_INTERNAL_ENV_VAR_PREFIX}) \
                cannot be accessed here"
            ),
        );
        return Err(err);
    }

    match (std::env::var(var), default) {
        (Ok(value), _) => {
            if is_secret {
                debug_assert!(placeholder_on_secret_access);
                let value = Value::from(SECRET_PLACEHOLDER.replace("{}", var));
                Ok(value)
            } else {
                if let Some(tracker) = tracker {
                    tracker(var, &value);

View on GitHub (pinned to 0267ce9170)

Solutions

  1. Rename the variable so it does not start with `_DBT` and access it under the new name.
  2. Stop depending on internal dbt variables; use documented public env vars or `flags`/`invocation_id` context members instead.
  3. Pass the needed value explicitly as a dbt var (`--vars`) or a non-reserved environment variable.

Example fix

// before (Jinja)
{{ env_var('_DBT_INVOCATION_TMP_DIR') }}
// after
{{ env_var('MY_TMP_DIR', default='/tmp') }}  <!-- avoid the reserved _DBT prefix -->
Defensive patterns

Strategy: validation

Validate before calling

// Reject reserved prefix before rendering
fn is_reserved(name: &str) -> bool { name.starts_with("_DBT") }

Prevention

When it happens

Trigger: Calling `{{ env_var('_DBT_SOMETHING') }}` with any name matching the `_DBT` prefix from Jinja. Unlike the secret check, no flag disables this — even `placeholder_on_secret_access = true` still errors at env_var.rs:64.

Common situations: Curious users or copy-pasted code attempt to read internal dbt variables (e.g. `_DBT_INTERNAL_...`) discovered via `env | log` debugging; scripts that blanket-export many `_DBT_*` vars and expect them visible in models.

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 dbt-labs/dbt-core@0267ce9170 (2026-09-07). Data as JSON: /api/errors/5295430efd9c0c0b. Report an issue: GitHub.