headroomlabs-ai/headroom · error · ValueError
{self.config_env_var} does not match config_payload
Error message
{self.config_env_var} does not match config_payload What it means
ValueError raised by DeploymentSpec.validate() in headroom/testing/harness.py when the config env var IS present but its JSON content does not equal spec.config_payload (json.loads(raw) != config_payload). This catches drift between the payload the test believes it deployed and what the environment actually carries — e.g. an older serialization, partial update, or different key ordering is fine (dict equality) but different values/keys are not.
Source
Thrown at headroom/testing/harness.py:398
config_env_var: str = "HEADROOM_PROXY_CONFIG_JSON"
def to_dict(self) -> dict[str, Any]:
return {
"command": list(self.command),
"env": dict(self.env),
"config_payload": dict(self.config_payload),
"config_env_var": self.config_env_var,
}
def validate(self) -> None:
"""Fail if the environment does not round-trip the full config payload."""
raw = self.env.get(self.config_env_var)
if raw is None:
raise ValueError(f"deployment env missing {self.config_env_var}")
parsed = json.loads(raw)
if parsed != self.config_payload:
raise ValueError(f"{self.config_env_var} does not match config_payload")
def _field_contract(
owner: Literal["headroom", "proxy"], cls: type[Any]
) -> tuple[FieldContract, ...]:
if not is_dataclass(cls):
raise TypeError(f"{cls!r} must be a dataclass")
out: list[FieldContract] = []
for field in cls.__dataclass_fields__.values():
default: Any = MISSING
if field.default is not MISSING:
default = field.default
elif field.default_factory is not MISSING: # type: ignore[attr-defined]
default = "<factory>"
out.append(
FieldContract(
owner=owner,
name=field.name,View on GitHub (pinned to 322425c43b)
Solutions
- Regenerate the env var from the payload: spec.env[spec.config_env_var] = json.dumps(spec.config_payload).
- If you must mutate config_payload, re-serialize immediately afterwards.
- Prefer the harness's own builder (to_dict/from_dict) over hand-assembling the env var.
Example fix
# before spec.config_payload['mode'] = 'cache' # mutated after injection spec.validate() # ValueError: does not match # after spec.config_payload['mode'] = 'cache' spec.env['HEADROOM_PROXY_CONFIG_JSON'] = json.dumps(spec.config_payload) spec.validate()
Defensive patterns
Strategy: validation
Validate before calling
import json
def env_matches_payload(spec) -> bool:
raw = spec.env.get(spec.config_env_var)
if raw is None:
return False
try:
return json.loads(raw) == spec.config_payload
except json.JSONDecodeError:
return False Try / catch
try:
spec.validate()
except ValueError as e:
if 'does not match' in str(e):
spec.env[spec.config_env_var] = json.dumps(spec.config_payload)
spec.validate()
else:
raise Prevention
- Single helper that always writes the env var from the payload — never edit one without the other.
- Run validate() in test setup, not just teardown.
When it happens
Trigger: Setting spec.env['HEADROOM_PROXY_CONFIG_JSON'] to a hand-written or stale JSON string instead of json.dumps(spec.config_payload); mutating spec.config_payload after injecting the env var; double-encoding (dumps of an already-JSON string).
Common situations: Tests that tweak config fields after building the deployment; fixtures caching serialized configs; copy-pasting an env var from a previous run's log.
Related errors
- deployment env missing {self.config_env_var}
- recommendations IO error at {path}: {source}
- bedrock_eventstream_parse_failed
- bedrock_eventstream_crc_mismatch
- Error: {e}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/8c6a55c8ec33d998.
Report an issue: GitHub.