{"record":{"id":"925d9ddf67a10261","repo":"MemPalace/mempalace","slug":"metadata-is-not-json-serializable-exc","errorCode":null,"errorMessage":"metadata is not JSON-serializable: {exc}","messagePattern":"metadata is not JSON-serializable: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"mempalace/logstream.py","lineNumber":165,"sourceCode":"    if \"\\x00\" in value:\n        raise ValueError(f\"{field_name} contains null bytes\")\n    value = strip_lone_surrogates(value)\n    size = len(value.encode(\"utf-8\"))\n    if size > max_bytes:\n        raise ValueError(f\"{field_name} is {size} bytes; maximum is {max_bytes} bytes\")\n    return value\n\n\ndef _sanitize_metadata(value) -> str:\n    \"\"\"Validate optional metadata dict and return its canonical JSON text.\"\"\"\n    if value is None:\n        return \"{}\"\n    if not isinstance(value, dict):\n        raise ValueError(\"metadata must be an object\")\n    try:\n        encoded = json.dumps(value, ensure_ascii=False, sort_keys=True)\n    except (TypeError, ValueError) as exc:\n        raise ValueError(f\"metadata is not JSON-serializable: {exc}\") from None\n    if len(encoded.encode(\"utf-8\")) > MAX_METADATA_BYTES:\n        raise ValueError(f\"metadata exceeds maximum size of {MAX_METADATA_BYTES} bytes\")\n    return encoded\n\n\nclass Logstream:\n    \"\"\"Durable append-only coordination log (events + artifacts).\n\n    Storage and threading mirror ``KnowledgeGraph``: one SQLite file in\n    WAL mode, a per-instance lock around writes, ``check_same_thread=False``\n    so the MCP HTTP server can call from worker threads.\n    \"\"\"\n\n    def __init__(\n        self,\n        db_path: str,\n        max_body_bytes: int = DEFAULT_MAX_BODY_BYTES,\n        max_artifact_bytes: int = DEFAULT_MAX_ARTIFACT_BYTES,","sourceCodeStart":147,"sourceCodeEnd":183,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/logstream.py#L147-L183","documentation":"The metadata dict could not be serialized with json.dumps (TypeError/ValueError), meaning it contains values JSON cannot represent — sets, custom objects, bytes, non-string dict keys, or NaN/Infinity with strict encoders. The original exception text is appended so the offending value is identifiable. This runs after the dict type check.","triggerScenarios":"append_event(metadata={'ids': {1, 2}}) (set); metadata={'when': datetime.now()} (datetime); metadata={'blob': b'x'} (bytes); metadata={(1,2): 'v'} (tuple key); nested dataclass instances.","commonSituations":"Reusing ORM/model objects as metadata; mixing stdlib types (Path, datetime, set) that are convenient in Python but not JSON-native; cache values from third-party libs leaking into annotations.","solutions":["Convert non-native values before the call: datetime.isoformat(), list(set), bytes.decode(), str(Path).","Use a default hook by pre-serializing: json.dumps(metadata, default=str) then json.loads the result before passing.","Replace unserializable entries with plain str/int/float/bool/None/list/dict."],"exampleFix":"// before\nls.append_event(..., metadata={\"at\": datetime.now(), \"tags\": {\"a\"}})\n// after\nls.append_event(..., metadata={\"at\": datetime.now(timezone.utc).isoformat(), \"tags\": [\"a\"]})","handlingStrategy":"validation","validationCode":"def json_safe_metadata(md: dict) -> dict:\n    return json.loads(json.dumps(md, ensure_ascii=False, default=str))\n\nmetadata = json_safe_metadata(metadata)  # datetime/set/Path become JSON-native","typeGuard":"def is_json_serializable(md) -> bool:\n    if not isinstance(md, dict):\n        return False\n    try:\n        json.dumps(md, ensure_ascii=False)\n        return True\n    except (TypeError, ValueError):\n        return False","tryCatchPattern":"try:\n    evt = ls.append_event(..., metadata=metadata)\nexcept ValueError as e:\n    if \"not JSON-serializable\" in str(e):\n        evt = ls.append_event(..., metadata=json.loads(json.dumps(metadata, default=str)))\n    else:\n        raise","preventionTips":["Convert datetime -> isoformat, set -> sorted list, Path/UUID -> str before building the dict.","Run is_json_serializable in unit tests over every metadata shape your producer emits."],"tags":["validation","logstream","metadata","json","serialization"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}