zylon-ai/private-gpt · critical · ValueError

Environment variable {env_var} is not set and not default wa

Error message

Environment variable {env_var} is not set and not default was provided

What it means

Raised by the custom YAML loader (load_yaml_with_envvars) when a settings file contains an ${ENV_VAR} substitution (or a comma-separated candidate list like ${VAR_A,VAR_B}) and none of the referenced environment variables is set, and no default after a colon (${VAR:default}) was provided. The loader refuses to silently substitute empty values, so startup fails at YAML parse time.

Source

Thrown at private_gpt/settings/yaml.py:36

    the value of the environment variable.
    """
    loader = SafeLoader(stream)

    def load_env_var(_, node) -> str:
        """Extract the matched value, expand env variable, and replace the match."""
        value = str(node.value).removeprefix("${").removesuffix("}")
        split = value.split(":", 1)
        env_vars = split[0].strip()
        env_value: str | None = None
        for env_var in env_vars.split(","):
            env_var = env_var.strip()
            env_value = environ.get(env_var) or env_value
            if env_value is not None:
                break
        value = env_value
        default = None if len(split) == 1 else split[1]
        if value is None and default is None:
            raise ValueError(
                f"Environment variable {env_var} is not set and not default was provided"
            )
        return value or default

    loader.add_implicit_resolver("env_var_replacer", _env_replace_matcher, None)
    loader.add_constructor("env_var_replacer", load_env_var)

    try:
        return loader.get_single_data()
    finally:
        loader.dispose()

View on GitHub (pinned to 4a030776a3)

Solutions

  1. Export the missing variable in the environment where private-gpt starts (verify with: echo "${VAR?unset}")
  2. Add a default in the YAML: change ${VAR} to ${VAR:fallback}
  3. If multiple names are possible use the comma form: ${PRIMARY_VAR,FALLBACK_VAR}
  4. For containers, ensure the variable is declared in compose 'environment:'/'env_file:' or the Kubernetes pod spec
  5. If the setting is optional, consider removing the placeholder from settings.yaml entirely

Example fix

# settings.yaml - before
llm:
  api_key: ${OPENAI_API_KEY}

# after (with default)
llm:
  api_key: ${OPENAI_API_KEY:dummy-key}
# or: export OPENAI_API_KEY=sk-... before starting
Defensive patterns

Strategy: validation

Validate before calling

import os, re

def check_env_placeholders(yaml_path: str) -> list[str]:
    text = open(yaml_path).read()
    missing = []
    for m in re.finditer(r"\$\{([^}]+)}", text):
        body = m.group(1)
        names, _, default = body.partition(":")
        if default:
            continue
        if not any(os.environ.get(n.strip()) for n in names.split(",")):
            missing.append(names)
    return missing  # non-empty => error 422 will occur

Type guard

null

Try / catch

try:
    cfg = load_yaml_with_envvars(open("settings.yaml"))
except ValueError as e:
    # e names the missing var; export it or add ':default' in the YAML
    raise SystemExit(str(e)) from e

Prevention

When it happens

Trigger: settings.yaml contains password: ${OPENAI_API_KEY} but the variable is unset in the shell/container; using ${DB_USER,DB_USERNAME} where neither is exported; forgetting the ':default' syntax when the value is optional; deploying with docker-compose/Kubernetes that does not pass the variable through (not listed in environment: or env_file).

Common situations: Works locally because the var is exported in the developer shell, then fails in CI or a container; renaming an environment variable without updating settings.yaml; sample settings files that reference vars the deployer never set; systemd/supervisor units that drop the user's environment.

Related errors


AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15). Data as JSON: /api/errors/6a934289e2fbecf2. Report an issue: GitHub.