ruvnet/RuView · error · ValueError

Environment must be one of

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.

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.

Appendix: 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)