headroomlabs-ai/headroom · error · ValueError
{key}={raw!r} is not an integer
Error message
{key}={raw!r} is not an integer What it means
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.
Source
Thrown at plugins/headroom-oauth2/src/headroom_oauth2/__init__.py:54
continue
k, v = (x.strip() for x in pair.split("=", 1))
if not k:
continue
if _ctrl(k) or _ctrl(v) or " " in k or ":" in k:
log.warning("headroom-oauth2: dropping malformed static header: %r", k)
continue
out[k] = v
return out
def _int(env, key):
raw = env.get(key)
if raw is None or not str(raw).strip():
return None
try:
return int(raw)
except ValueError:
raise ValueError(f"{key}={raw!r} is not an integer") from None
def provider_from_env(env: dict | None = None) -> OAuth2ClientCredentials | None:
"""Build a provider from ``HEADROOM_OAUTH2_*`` env vars, or None if TOKEN_URL is unset.
Raises ValueError on malformed config so callers can fail closed.
"""
env = os.environ if env is None else env
token_url = env.get("HEADROOM_OAUTH2_TOKEN_URL")
if not token_url:
return None
allow_insecure = env.get("HEADROOM_OAUTH2_ALLOW_INSECURE", "").strip().lower() in (
"1",
"true",
"yes",
)
if allow_insecure:
log.warning("headroom-oauth2: ALLOW_INSECURE set -- token endpoint TLS check disabled")View on GitHub (pinned to 322425c43b)
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
Example fix
# before environment: - HEADROOM_OAUTH2_TIMEOUT_SECONDS=30s # or "30" with literal quotes # after environment: - HEADROOM_OAUTH2_TIMEOUT_SECONDS=30
Defensive patterns
Strategy: validation
Validate before calling
def get_int_env(env: dict, key: str) -> int | None:
raw = env.get(key)
if raw is None or not str(raw).strip():
return None
try:
return int(str(raw).strip())
except ValueError:
raise ValueError(f"{key} must be an integer, got {raw!r}") from None
get_int_env(os.environ, "HEADROOM_OAUTH2_TIMEOUT_SECONDS") # before starting the proxy Type guard
def int_env_ok(raw: str | None) -> bool:
if raw is None or not str(raw).strip():
return True # unset/empty is fine
try:
int(str(raw).strip()); return True
except ValueError:
return False Try / catch
try:
provider = provider_from_env()
except ValueError as e:
raise SystemExit(f"aborting: oauth2 env invalid: {e}") from e # fail loud at deploy time Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- headroom-oauth2 misconfigured: {e}
- auth_style must be 'post' or 'basic'
- unknown compaction format {resolved_format!r}; expected one
- token_url is required
- client_id and client_secret are required
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/278cf643000469fc.
Report an issue: GitHub.