{"record":{"id":"fa6f39dcf42da113","repo":"headroomlabs-ai/headroom","slug":"unserializable-config-value-type-value-name","errorCode":null,"errorMessage":"unserializable config value: {type(value).__name__}","messagePattern":"unserializable config value: (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"headroom/transforms/config_compressor.py","lineNumber":79,"sourceCode":"    \"\"\"Parse TOML with the stdlib parser (or the tomli backport); None on error.\"\"\"\n    try:\n        import tomllib\n    except ModuleNotFoundError:  # pragma: no cover - Python < 3.11 only\n        try:\n            import tomli as tomllib  # type: ignore[no-redef]\n        except ModuleNotFoundError:\n            return None\n    try:\n        return cast(\"dict[str, Any]\", tomllib.loads(content))\n    except (tomllib.TOMLDecodeError, ValueError):\n        return None\n\n\ndef _json_default(value: Any) -> str:\n    \"\"\"Render TOML date/time values as ISO strings; bail on anything else.\"\"\"\n    if isinstance(value, dt.datetime | dt.date | dt.time):\n        return value.isoformat()\n    raise TypeError(f\"unserializable config value: {type(value).__name__}\")\n\n\n@dataclass\nclass ConfigCompressorConfig:\n    \"\"\"Configuration for structured-config compression.\"\"\"\n\n    # Emit the CCR-marked comment/blank elision tier. The router wires this\n    # to its ccr_inject_marker setting; lossless mode turns it off.\n    enable_ccr: bool = True\n    # Bridge TOML array-of-tables to SmartCrusher csv-schema (Tier 3). Rides\n    # CCR for recovery, so it only runs when enable_ccr is also on.\n    enable_schema_fold: bool = True\n    # Only adopt a result that is strictly smaller than the original.\n    min_savings_chars: int = 1\n\n\n@dataclass\nclass ConfigCompressionResult:","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/transforms/config_compressor.py#L61-L97","documentation":"Raised by _json_default in config_compressor.py when JSON-serializing parsed TOML content encounters a value that is neither a TOML date/time nor a JSON-native type. The hook renders dt.datetime/dt.date/dt.time as ISO strings and treats everything else (e.g. tomllib's returned types that stray from the allowlist) as unserializable, failing loudly instead of emitting lossy config.","triggerScenarios":"Serializing a TOML config that contains a value type _json_default does not whitelist — any non date/time custom object reaching json.dumps(default=_json_default) during structured-config compression.","commonSituations":"A TOML file with exotic inline values, or a code change that puts non-TOML objects into the dict before serialization; version drift in tomllib's returned types.","solutions":["Inspect the TypeError's type name to find the offending key in the TOML, and replace that value with a string/number/bool.","If the type is legitimately serializable, extend _json_default with an isinstance branch for it (e.g. Decimal -> str(value)).","Keep config files to plain TOML scalars, arrays, and tables."],"exampleFix":"# before\ndef _json_default(value):\n    if isinstance(value, dt.datetime | dt.date | dt.time):\n        return value.isoformat()\n    raise TypeError(f\"unserializable config value: {type(value).__name__}\")\n\n# after — add a branch for the new type\ndef _json_default(value):\n    if isinstance(value, dt.datetime | dt.date | dt.time):\n        return value.isoformat()\n    if isinstance(value, decimal.Decimal):\n        return str(value)\n    raise TypeError(f\"unserializable config value: {type(value).__name__}\")","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    payload = json.dumps(config_dict, default=_json_default)\nexcept TypeError as e:\n    if \"unserializable config value\" in str(e):\n        locate_offending_key(config_dict)  # walk dict, test json.dumps per leaf\n        raise ConfigError(f\"config contains unsupported value: {e}\") from e\n    raise","preventionTips":["Keep TOML configs to scalars, arrays, and tables only.","Extend _json_default when introducing a new serializable value type.","Validate configs by round-tripping (parse -> dump) in CI."],"tags":["serialization","toml","json","configuration"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}