{"record":{"id":"bd3ff5c7a74bd301","repo":"can1357/oh-my-pi","slug":"field-must-be-a-boolean","errorCode":null,"errorMessage":"{field} must be a boolean","messagePattern":"(.+?) must be a boolean","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/protocol.py","lineNumber":213,"sourceCode":"def _optional_literal(\n    value: object, allowed: frozenset[str], *, field: str\n) -> str | None:\n    if value is None:\n        return None\n    return _require_literal(value, allowed, field=field)\n\n\ndef _require_str(payload: JsonObject, field: str) -> str:\n    value = payload.get(field)\n    if not isinstance(value, str):\n        raise ValueError(f\"{field} must be a string\")\n    return value\n\n\ndef _require_bool(payload: JsonObject, field: str) -> bool:\n    value = payload.get(field)\n    if not isinstance(value, bool):\n        raise ValueError(f\"{field} must be a boolean\")\n    return value\n\n\ndef _optional_str(payload: JsonObject, field: str) -> str | None:\n    value = payload.get(field)\n    if value is None:\n        return None\n    if not isinstance(value, str):\n        raise ValueError(f\"{field} must be a string\")\n    return value\n\n\ndef _optional_str_list(payload: JsonObject, field: str) -> tuple[str, ...]:\n    \"\"\"Parse an optional string-or-array-of-strings field.\n\n    The agent's `systemPrompt` (and similar) became `string[]` server-side\n    when multi-prompt support landed. Older daemons still emit a bare string,\n    so we accept either shape. Returns an empty tuple when the field is","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/protocol.py#L195-L231","documentation":"`_require_bool` validates that a required payload field is a JSON true/false. It raises ValueError when the field is missing or holds any non-boolean value. This guarantees parsed result objects have genuine booleans rather than truthy ints or strings.","triggerScenarios":"parse_fast_mode_result receives a payload where the required boolean field is absent, or is 0/1, \"true\"/\"false\" (strings), or null.","commonSituations":"A server serializes booleans as 0/1 (common in DB-backed responses); a mock fixture uses \"true\" as a string; a schema change made the field optional on the wire but the parser still requires it.","solutions":["Inspect the payload field and convert it to a real bool (bool(int(value)) for 0/1, value == \"true\" for strings)","Fix the producer so it emits JSON true/false","If the field can legitimately be absent, normalize the payload or skip parse_fast_mode_result for it"],"exampleFix":"# before\nresult = parse_fast_mode_result({\"enabled\": \"true\"})  # ValueError: enabled must be a boolean\n# after\nraw = {\"enabled\": \"true\"}\nresult = parse_fast_mode_result({\"enabled\": raw[\"enabled\"] == \"true\"})","handlingStrategy":"validation","validationCode":"def ensure_bool(payload: dict, field: str) -> None:\n    if not isinstance(payload.get(field), bool):\n        raise TypeError(f\"{field!r} must be a boolean, got {payload.get(field)!r}\")\n\nensure_bool(payload, \"enabled\")\nparse_fast_mode_result(payload)","typeGuard":"def is_bool_field(payload: dict, field: str) -> bool:\n    return isinstance(payload.get(field), bool)","tryCatchPattern":"try:\n    result = parse_fast_mode_result(payload)\nexcept ValueError as e:\n    logger.error(\"fast mode result rejected\", extra={\"payload\": payload, \"error\": str(e)})\n    result = None  # fall back to non-fast path","preventionTips":["Emit strict JSON booleans from servers (not 0/1 or \"true\")","Add a schema-validation step before parsing RPC responses","Watch for Python gotchas: bool is a subclass of int, so check bool first","Version-check the wire protocol on connect"],"tags":["python","rpc","type-validation","boolean"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}