headroomlabs-ai/headroom · error · ValueError
expected a JSON object of header name/value strings
Error message
expected a JSON object of header name/value strings
What it means
ValueError from _coerce in headroom/settings_store.py when a 'header-map' field receives a non-dict value that is not even parseable JSON (json.loads raises ValueError/TypeError, line 808). This guards settings like OPENAI_TARGET_API_HEADERS / openai_extra_headers, which must be a JSON object of header-name → header-value strings. The original JSON parse error is chained (__cause__). Reported per-field via SettingsValidationError.field_errors.
Source
Thrown at headroom/settings_store.py:808
return number
if field.type == "enum":
token = str(value)
if token not in field.choices:
raise ValueError(f"{token!r} not one of {list(field.choices)}")
return token
if field.type == "csv-list":
tokens = value if isinstance(value, list | tuple) else str(value).split(",")
tokens = [str(token).strip() for token in tokens]
tokens = [token for token in tokens if token]
return ",".join(tokens) if tokens else None
if field.type == "header-map":
if isinstance(value, dict):
parsed = value
else:
try:
parsed = json.loads(str(value))
except (ValueError, TypeError) as exc:
raise ValueError("expected a JSON object of header name/value strings") from exc
if not isinstance(parsed, dict) or not all(
isinstance(k, str) and isinstance(v, str) for k, v in parsed.items()
):
raise ValueError("expected a JSON object of header name/value strings")
return json.dumps(parsed, sort_keys=True) if parsed else None
# str
token = str(value)
return token if token != "" else None
def _serialize(field: SettingField, value: Any) -> str:
"""Serialize a coerced value to the exact string its env var expects."""
if field.type in ("bool", "optional-bool"):
return "1" if value else "0"
return str(value)
def validate(values: dict[str, Any]) -> dict[str, Any]:View on GitHub (pinned to 322425c43b)
Solutions
- Supply a valid JSON object: '{"X-Header": "value"}' — keys and values both strings.
- Single-quote the whole env value in shell so inner double quotes survive.
- Validate with json.loads in a pre-deploy check so shell mangling is caught before startup.
Example fix
# before
OPENAI_TARGET_API_HEADERS="Authorization: Bearer tkn" # not JSON
# after
OPENAI_TARGET_API_HEADERS='{"Authorization": "Bearer tkn"}' Defensive patterns
Strategy: validation
Validate before calling
import json
def parseable_header_map(v) -> bool:
if isinstance(v, dict):
return True
try:
json.loads(str(v))
return True
except (ValueError, TypeError):
return False Try / catch
except SettingsValidationError as e:
for key, msg in e.field_errors.items():
if 'header' in msg:
raise SystemExit(f'{key} must be a JSON object of headers, got: {payload[key]!r}') Prevention
- Test header-map env vars with json.loads in CI.
- Prefer writing the setting through the API/JSON store (a dict) over raw env strings.
When it happens
Trigger: save({'openai_extra_headers': 'Authorization: Bearer x'}) — a header-line syntax instead of JSON; a single quoted header value; truncated JSON from env-var length limits; unquoted braces in a shell variable.
Common situations: Operators used to curl -H syntax pasting header lines into the setting; env vars mangled by quoting/escaping in docker-compose or Kubernetes YAML (the $ and quotes break JSON); multi-line values collapsed by .env parsers.
Related errors
- {env_var} must be a JSON object of header name/value strings
- magika inference failed: {0}
- invalid pipeline config TOML: {0}
- recommendations file not found: {0}
- items_json must be JSON: {e}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/f6a8c1553d919c75.
Report an issue: GitHub.