{"record":{"id":"278cf643000469fc","repo":"headroomlabs-ai/headroom","slug":"key-raw-r-is-not-an-integer","errorCode":null,"errorMessage":"{key}={raw!r} is not an integer","messagePattern":"(.+?)=(.+?) is not an integer","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"plugins/headroom-oauth2/src/headroom_oauth2/__init__.py","lineNumber":54,"sourceCode":"            continue\n        k, v = (x.strip() for x in pair.split(\"=\", 1))\n        if not k:\n            continue\n        if _ctrl(k) or _ctrl(v) or \" \" in k or \":\" in k:\n            log.warning(\"headroom-oauth2: dropping malformed static header: %r\", k)\n            continue\n        out[k] = v\n    return out\n\n\ndef _int(env, key):\n    raw = env.get(key)\n    if raw is None or not str(raw).strip():\n        return None\n    try:\n        return int(raw)\n    except ValueError:\n        raise ValueError(f\"{key}={raw!r} is not an integer\") from None\n\n\ndef provider_from_env(env: dict | None = None) -> OAuth2ClientCredentials | None:\n    \"\"\"Build a provider from ``HEADROOM_OAUTH2_*`` env vars, or None if TOKEN_URL is unset.\n\n    Raises ValueError on malformed config so callers can fail closed.\n    \"\"\"\n    env = os.environ if env is None else env\n    token_url = env.get(\"HEADROOM_OAUTH2_TOKEN_URL\")\n    if not token_url:\n        return None\n    allow_insecure = env.get(\"HEADROOM_OAUTH2_ALLOW_INSECURE\", \"\").strip().lower() in (\n        \"1\",\n        \"true\",\n        \"yes\",\n    )\n    if allow_insecure:\n        log.warning(\"headroom-oauth2: ALLOW_INSECURE set -- token endpoint TLS check disabled\")","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/plugins/headroom-oauth2/src/headroom_oauth2/__init__.py#L36-L72","documentation":"The headroom-oauth2 plugin parses `HEADROOM_OAUTH2_*` integer settings (e.g. timeout/skew env vars) with a strict `_int` helper: a value that is set, non-empty, and not parseable by `int()` raises ValueError naming the key and the raw value. This is intentional fail-closed behavior — a malformed numeric setting must abort startup rather than be silently defaulted.","triggerScenarios":"Setting e.g. `HEADROOM_OAUTH2_TIMEOUT_SECONDS=30s`, `=thirty`, `=30.5` (int() rejects decimals), or a value with stray whitespace/quotes like `\"60\"` with literal quotes from a config file, while `HEADROOM_OAUTH2_TOKEN_URL` is also set so the provider is constructed.","commonSituations":"Docker-compose/Kubernetes env values quoted as strings with units; `.env` files where a value was edited and left non-numeric; YAML configs using `timeout: 30s` style durations pasted into env vars; `30.0` floats from scripts that write env files.","solutions":["Set the variable to a plain integer string: `HEADROOM_OAUTH2_TIMEOUT_SECONDS=30` (no units, no quotes, no decimals — use `30` not `30.5`)","Inspect the exact value the message shows: `echo \"$HEADROOM_OAUTH2_TIMEOUT_SECONDS\" | cat -A` to expose hidden quotes/whitespace/CRLF","Remove the variable entirely if you want the built-in default — unset/empty is accepted and skipped, only malformed non-empty values fail"],"exampleFix":"# before\nenvironment:\n  - HEADROOM_OAUTH2_TIMEOUT_SECONDS=30s   # or \"30\" with literal quotes\n\n# after\nenvironment:\n  - HEADROOM_OAUTH2_TIMEOUT_SECONDS=30","handlingStrategy":"validation","validationCode":"def get_int_env(env: dict, key: str) -> int | None:\n    raw = env.get(key)\n    if raw is None or not str(raw).strip():\n        return None\n    try:\n        return int(str(raw).strip())\n    except ValueError:\n        raise ValueError(f\"{key} must be an integer, got {raw!r}\") from None\n\nget_int_env(os.environ, \"HEADROOM_OAUTH2_TIMEOUT_SECONDS\")  # before starting the proxy","typeGuard":"def int_env_ok(raw: str | None) -> bool:\n    if raw is None or not str(raw).strip():\n        return True  # unset/empty is fine\n    try:\n        int(str(raw).strip()); return True\n    except ValueError:\n        return False","tryCatchPattern":"try:\n    provider = provider_from_env()\nexcept ValueError as e:\n    raise SystemExit(f\"aborting: oauth2 env invalid: {e}\") from e  # fail loud at deploy time","preventionTips":["Lint integer env vars in a pre-deploy config check","Avoid units/quotes/decimals in env values — plain integer strings only","Unset optional numeric vars rather than setting junk values"],"tags":["configuration","env-vars","oauth2","fail-closed"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}