headroomlabs-ai/headroom · error · SettingsValidationError
settings validation failed: unknown={unknown_keys} errors={f
Error message
settings validation failed: unknown={unknown_keys} errors={field_errors} What it means
SettingsValidationError is the aggregate error raised when a settings payload fails validation: unknown_keys lists keys not in the registry and field_errors maps each bad field key to its _coerce message (bool/number/range/enum/header-map failures). It carries structured detail (attributes unknown_keys, field_errors) precisely so the API layer can map unknown keys to HTTP 400 and field errors to 422. The f-string at line 729/848 renders both into the message.
Source
Thrown at headroom/settings_store.py:848
fails coercion. Returns the coerced dict (``None`` values dropped) on success.
"""
values = _normalize_values(values)
unknown = [key for key in values if key not in _BY_KEY]
field_errors: dict[str, str] = {}
coerced: dict[str, Any] = {}
for key, value in values.items():
field = _BY_KEY.get(key)
if field is None:
continue
try:
result = _coerce(field, value)
except (ValueError, TypeError) as exc:
field_errors[key] = str(exc)
continue
if result is not None:
coerced[key] = result
if unknown or field_errors:
raise SettingsValidationError(unknown, field_errors)
return coerced
def load() -> dict[str, Any]:
"""Return validated stored values. Fail-open: ``{}`` if missing or corrupt."""
path = paths.settings_path()
try:
raw = path.read_text(encoding="utf-8")
except FileNotFoundError:
return {}
except OSError as exc:
logger.warning("settings_store: cannot read %s: %s", path, exc)
return {}
try:
data = json.loads(raw)
except (ValueError, UnicodeDecodeError) as exc:
logger.warning("settings_store: ignoring corrupt settings.json: %s", exc)
return {}View on GitHub (pinned to 322425c43b)
Solutions
- Read the two lists in the message: fix or remove every key in unknown=, and correct each field in errors= using its per-field message.
- If keys are unknown because of a version rename, update the client to the current key names in headroom.settings_store.SETTINGS.
- Programmatically iterate exc.unknown_keys / exc.field_errors instead of parsing the message string.
Example fix
# before
save({'proxy_mod': 'cache', 'max_retries': -1}) # SettingsValidationError
# after
save({'proxy_mode': 'cache', 'max_retries': 0}) Defensive patterns
Strategy: try-catch
Validate before calling
from headroom.settings_store import _BY_KEY, SETTINGS
def prevalidate(payload: dict) -> tuple[list, dict]:
unknown = [k for k in payload if k not in _BY_KEY]
errors = {}
for k, v in payload.items():
f = _BY_KEY.get(k)
if f is None:
continue
try:
_coerce(f, v) # or replicate the checks per type
except ValueError as e:
errors[k] = str(e)
return unknown, errors Try / catch
from headroom.settings_store import SettingsValidationError
try:
store.save(payload)
except SettingsValidationError as e:
bad = set(e.unknown_keys) | set(e.field_errors)
payload = {k: v for k, v in payload.items() if k not in bad}
store.save(payload) # retry with clean subset; log what was dropped Prevention
- Map SettingsValidationError to 400 (unknown keys) / 422 (field errors) in HTTP layers, mirroring the library's intent.
- Prevalidate payloads against the SETTINGS registry in tests.
- Never parse the message string; use the structured attributes.
When it happens
Trigger: Calling the save/validate path with a payload containing an unrecognized key (typo like 'proxy_mod') or any invalid value that _coerce rejects (see errors 362-370). Also raised directly by _normalize_values when env aliases conflict (error 361).
Common situations: First-time integrations guessing setting names; stale clients from older versions sending renamed keys; bulk config imports where one bad row should not abort everything.
Related errors
- expected a boolean, got {value!r}
- expected a number, got {value!r}
- expected an integer, got {value!r}
- expected a finite number, got {value!r}
- must be >= {field.minimum}
AI-assisted analysis of headroomlabs-ai/headroom@322425c43b (2026-08-15).
Data as JSON: /api/errors/aa0e1f7549c3cb83.
Report an issue: GitHub.