headroomlabs-ai/headroom · error · ValueError
{env_var} must be a JSON object of header name/value strings
Error message
{env_var} must be a JSON object of header name/value strings What it means
resolve_extra_headers() parses the extra-headers override (CLI flag or the ANTHROPIC_TARGET_API_HEADERS / OPENAI_TARGET_API_HEADERS env vars) as JSON. This raise site fires when json.loads() itself fails — the value is not parseable JSON at all (trailing commas, single quotes, missing quotes around keys, shell-mangled escaping). The result is a ValueError surfaced by the proxy CLI, which prints 'error: ...' and exits 1.
Source
Thrown at headroom/providers/registry.py:152
def resolve_extra_headers(
cli_value: str | None,
env_var: str,
*,
environ: Mapping[str, str] | None = None,
) -> dict[str, str] | None:
"""Resolve extra headers to merge into (and override) forwarded provider requests.
Accepts a JSON object string from CLI or env (CLI wins). Returns ``None`` if unset.
Raises ``ValueError`` on invalid JSON or a non-string-keyed/valued object.
"""
env = environ or os.environ
raw = cli_value or env.get(env_var)
if not raw:
return None
try:
parsed = json.loads(raw)
except (ValueError, TypeError) as exc:
raise ValueError(f"{env_var} must be 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(f"{env_var} must be a JSON object of header name/value strings")
return parsed or None
def resolve_api_targets(overrides: ProviderApiOverrides) -> ProviderApiTargets:
"""Resolve normalized upstream provider targets from configured overrides."""
return ProviderApiTargets(
anthropic=_normalize_api_url(overrides.anthropic, default=DEFAULT_ANTHROPIC_API_URL),
openai=_normalize_api_url(overrides.openai, default=DEFAULT_OPENAI_API_URL),
gemini=_normalize_api_url(overrides.gemini, default=DEFAULT_GEMINI_API_URL),
cloudcode=_normalize_api_url(overrides.cloudcode, default=DEFAULT_CLOUDCODE_API_URL),
vertex=_normalize_api_url(overrides.vertex, default=DEFAULT_VERTEX_API_URL),
)
View on GitHub (pinned to 322425c43b)
Solutions
- Set the value to a valid JSON object of string keys and string values, e.g. ANTHROPIC_TARGET_API_HEADERS='{"X-Title":"my-app"}'.
- Validate before launch: python -c "import json,sys; json.loads(sys.argv[1])" "$VALUE".
- Prefer the CLI flag over the env var so shell history shows the exact string, and use single quotes around the JSON to prevent shell interpolation.
Example fix
# before
export ANTHROPIC_TARGET_API_HEADERS="{'X-Title':'my-app'}" # ValueError
# after
export ANTHROPIC_TARGET_API_HEADERS='{"X-Title": "my-app"}' Defensive patterns
Strategy: validation
Validate before calling
import json
def valid_extra_headers(raw: str | None) -> bool:
if not raw:
return True
try:
parsed = json.loads(raw)
except (ValueError, TypeError):
return False
return isinstance(parsed, dict) and all(
isinstance(k, str) and isinstance(v, str) for k, v in parsed.items()
) Try / catch
try:
headers = resolve_extra_headers(cli_value, "ANTHROPIC_TARGET_API_HEADERS")
except ValueError as exc:
sys.exit(f"bad extra headers config: {exc}") Prevention
- Lint env/config files with a JSON parse check before starting the proxy.
- Use single-quoted shell strings around JSON to avoid interpolation mangling.
- Keep header injection values in a config file (loaded and json-parsed) instead of inline env strings.
When it happens
Trigger: Launching the headroom proxy with --anthropic-extra-headers / --openai-extra-headers (or the corresponding TARGET_API_HEADERS env var) set to a string that is not valid JSON, e.g. "{'X-Foo':'bar'}" or 'X-Foo: bar'.
Common situations: Writing JSON in a shell with incorrect quoting so the value reaching Python is truncated or single-quoted; using YAML-style or header-line syntax instead of a JSON object; secrets injected with newline or quote characters that break the parse.
Related errors
- Error: {e}
- {_WRAP_PROXY_TIMEOUT_ENV} must be a positive integer number
- HEADROOM_LEARN_CLI={cli_override!r} is not a supported CLI.
- No LLM API key found. headroom learn needs one of: export
- `{cmd[0]}` not found in PATH. Install it or use a different
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/9a0bb57d8ddaaedd.
Report an issue: GitHub.