{"record":{"id":"57442155af12940e","repo":"can1357/oh-my-pi","slug":"rpc-payload-must-be-json-serializable","errorCode":null,"errorMessage":"RPC payload must be JSON-serializable","messagePattern":"RPC payload must be JSON-serializable","errorType":"exception","errorClass":"RpcError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/client.py","lineNumber":294,"sourceCode":"    try:\n        process.wait(timeout=1.0)\n    except subprocess.TimeoutExpired:\n        pass\n\n\ndef _clone_json_value(value: object) -> JsonValue:\n    if value is None or isinstance(value, (str, int, float, bool)):\n        return cast(JsonValue, value)\n    if isinstance(value, list):\n        return [_clone_json_value(item) for item in value]\n    if isinstance(value, dict):\n        cloned: JsonObject = {}\n        for key, item in value.items():\n            if not isinstance(key, str):\n                raise RpcError(\"RPC payload objects must use string keys\")\n            cloned[key] = _clone_json_value(item)\n        return cloned\n    raise RpcError(\"RPC payload must be JSON-serializable\")\n\n\ndef _clone_json_object(value: object) -> JsonObject:\n    if not isinstance(value, dict):\n        raise RpcError(\"RPC response payload must be an object\")\n    return cast(JsonObject, _clone_json_value(value))\n\n\nclass RpcError(RuntimeError):\n    \"\"\"Base exception for the Python RPC client.\"\"\"\n\n\nclass RpcTimeoutError(RpcError):\n    \"\"\"Raised when the server does not respond before a timeout.\"\"\"\n\n\nclass RpcProcessExitError(RpcError):\n    \"\"\"Raised when the RPC process exits while a request is pending.\"\"\"","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/client.py#L276-L312","documentation":"_clone_json_value raises this when it encounters a value that is not JSON-serializable (dict, list, str, int, float, bool, None) while deep-copying an RPC payload. It enforces strict JSON semantics before sending so the wire format is never invalid.","triggerScenarios":"Passing objects like datetime, set, bytes, custom class instances, pathlib.Path, or Decimal inside request params to any client method that sends a payload.","commonSituations":"Including datetime.now() timestamps, sets of tags, or ORM model objects directly in params; passing Path objects from file-handling code into RPC arguments.","solutions":["Convert non-JSON values before sending: isoformat() for datetimes, sorted(list) for sets, str(path) for Paths.","Use json.loads(json.dumps(payload, default=str)) as a normalization step, or add a default serializer.","Pre-validate the payload with json.dumps(payload) in a try/except before making the call to localize the offending field.","Add explicit serialization helpers at the boundary where payload data is constructed."],"exampleFix":"// before\nparams = {\"due\": datetime.now(), \"tags\": {\"a\", \"b\"}}\nawait client.prompt(params)\n\n// after\nparams = {\"due\": datetime.now().isoformat(), \"tags\": sorted({\"a\", \"b\"})}\nawait client.prompt(params)","handlingStrategy":"validation","validationCode":"def assert_json_serializable(payload):\n    json.dumps(payload)  # raises TypeError for datetime/set/bytes/etc.","typeGuard":"def is_json_value(v) -> bool:\n    if v is None or isinstance(v, (str, bool, int, float)):\n        return True\n    if isinstance(v, dict):\n        return all(isinstance(k, str) and is_json_value(x) for k, x in v.items())\n    if isinstance(v, list):\n        return all(is_json_value(x) for x in v)\n    return False","tryCatchPattern":"try:\n    await client.prompt(params)\nexcept RpcError as exc:\n    if \"JSON-serializable\" in str(exc):\n        params = json.loads(json.dumps(params, default=str))\n        await client.prompt(params)\n    else:\n        raise","preventionTips":["Convert datetimes with .isoformat(), sets with sorted(), Paths with str()","Never put ORM/model instances directly into params","Run a json.dumps smoke test on payloads in tests"],"tags":["rpc","json","serialization","payload-validation"],"backgroundTag":"json-serializable-payload","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}