ruvnet/RuView · error · ValueError

Environment must be one of: {allowed_environments}

Error message

Environment must be one of: {allowed_environments}

What it means

Pydantic v2 @field_validator on Settings.environment in archive/v1/src/config/settings.py. It enforces exact membership in ['development', 'staging', 'production'] — a case-sensitive check with no .lower() normalization, so 'Production', 'prod', 'dev', and 'test' are all rejected. Because this is a pydantic-settings class, the value typically arrives from the ENVIRONMENT env var, and an invalid value fails at Settings() construction, usually at application startup.

Source

Thrown at archive/v1/src/config/settings.py:182

        env_file=".env",
        env_file_encoding="utf-8",
        case_sensitive=False,
        # Tolerate `.env` keys that this Settings model doesn't declare
        # (e.g., NPM_TOKEN, DOCKER_HUB_TOKEN, PYPI_TOKEN used by other
        # tooling). Without `extra="ignore"` pydantic-settings 2.x
        # raises `ValidationError: Extra inputs are not permitted` and
        # leaks the offending values into the error message — a real
        # security concern for secret tokens. See verify.py / `./verify`.
        extra="ignore",
    )
    
    @field_validator("environment")
    @classmethod
    def validate_environment(cls, v):
        """Validate environment setting."""
        allowed_environments = ["development", "staging", "production"]
        if v not in allowed_environments:
            raise ValueError(f"Environment must be one of: {allowed_environments}")
        return v
    
    @field_validator("log_level")
    @classmethod
    def validate_log_level(cls, v):
        """Validate log level setting."""
        allowed_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
        if v.upper() not in allowed_levels:
            raise ValueError(f"Log level must be one of: {allowed_levels}")
        return v.upper()
    
    @field_validator("pose_confidence_threshold")
    @classmethod
    def validate_confidence_threshold(cls, v):
        """Validate confidence threshold."""
        if not 0.0 <= v <= 1.0:
            raise ValueError("Confidence threshold must be between 0.0 and 1.0")
        return v

View on GitHub (pinned to 4685618388)

Solutions

  1. Set ENVIRONMENT to the exact lowercase full word: development, staging, or production
  2. Strip whitespace and avoid inline comments on the ENVIRONMENT line in .env files
  3. Normalize in a wrapper if you must accept shorthand (env = {'dev': 'development', 'prod': 'production'}.get(raw, raw))
  4. If you genuinely need a new environment like 'ci', add it to allowed_environments in the validator

Example fix

# before
ENVIRONMENT=prod

# after
ENVIRONMENT=production
Defensive patterns

Strategy: validation

Validate before calling

ALLOWED = {"development", "staging", "production"}
raw = os.environ.get("ENVIRONMENT", "development").strip().lower()
environment = {"dev": "development", "prod": "production", "staging": "staging"}.get(raw, raw)
assert environment in ALLOWED, f"ENVIRONMENT must be one of {sorted(ALLOWED)}, got {raw!r}"

Type guard

def is_valid_environment(v: str) -> bool:
    return v in {"development", "staging", "production"}

Try / catch

from pydantic import ValidationError
try:
    settings = Settings()
except ValidationError as e:
    if any(err["loc"][-1] == "environment" for err in e.errors()):
        raise SystemExit("ENVIRONMENT must be exactly development|staging|production (lowercase, no shorthand)") from e
    raise

Prevention

When it happens

Trigger: ENVIRONMENT=dev, ENVIRONMENT=prod, or ENVIRONMENT=test (common shorthand); ENVIRONMENT=Production (capitalized — rejected by the case-sensitive comparison); trailing whitespace like 'production ' from .env files; CI setting ENVIRONMENT=ci.

Common situations: Copying shorthand values from docker-compose or Makefiles of other projects; capitalized values in .env files; whitespace introduced by 'KEY=value # comment' parsing; new environments (ci, local, qa) not being added to the allow-list.

Related errors


AI-assisted analysis of ruvnet/RuView@4685618388 (2026-08-16). Data as JSON: /api/errors/8bdd3f32cfd7dc9c. Report an issue: GitHub.