{"record":{"id":"4bf304b1d9a9f132","repo":"can1357/oh-my-pi","slug":"cycle-model-response-did-not-include-a-model","errorCode":null,"errorMessage":"cycle_model response did not include a model","messagePattern":"cycle_model response did not include a model","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/protocol.py","lineNumber":1485,"sourceCode":"        summary=str(payload.get(\"summary\", \"\")),\n        short_summary=_optional_str(payload, \"shortSummary\"),\n        first_kept_entry_id=str(payload.get(\"firstKeptEntryId\", \"\")),\n        tokens_before=int(payload.get(\"tokensBefore\", 0)),\n        details=_clone_json_value(payload.get(\"details\"), field=\"compaction.details\")\n        if \"details\" in payload\n        else None,\n        preserve_data=_optional_json_object(\n            payload.get(\"preserveData\"), field=\"compaction.preserveData\"\n        ),\n    )\n\n\ndef parse_model_cycle_result(payload: JsonObject | None) -> ModelCycleResult | None:\n    if payload is None:\n        return None\n    model = parse_model_info(cast(JsonObject, payload.get(\"model\")))\n    if model is None:\n        raise ValueError(\"cycle_model response did not include a model\")\n    return ModelCycleResult(\n        model=model,\n        thinking_level=cast(ThinkingLevel | None, payload.get(\"thinkingLevel\")),\n        is_scoped=bool(payload.get(\"isScoped\", False)),\n    )\n\n\ndef parse_thinking_level_cycle_result(\n    payload: JsonObject | None,\n) -> ThinkingLevelCycleResult | None:\n    if payload is None or payload.get(\"level\") is None:\n        return None\n    return ThinkingLevelCycleResult(level=cast(ThinkingLevel, payload[\"level\"]))\n\n\ndef parse_cancellation_result(payload: JsonObject | None) -> CancellationResult:\n    return CancellationResult(cancelled=bool((payload or {}).get(\"cancelled\", False)))\n","sourceCodeStart":1467,"sourceCodeEnd":1503,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/protocol.py#L1467-L1503","documentation":"parse_model_cycle_result() parses the response of a cycle_model RPC. A non-null payload must contain a \"model\" object parseable by parse_model_info; if the key is absent or unparseable, the parser raises ValueError because ModelCycleResult is meaningless without a model.","triggerScenarios":"Server returns a payload for cycle_model without a \"model\" key (e.g. {\"ok\": true}), returns null inside the payload, or returns a malformed model object that parse_model_info rejects as None.","commonSituations":"Server had no model to cycle to but still returned a non-null payload; protocol version drift where the response field was renamed; custom/RPC server implementations forgetting to include model info; mocks built by hand.","solutions":["Fix the server to always include a valid \"model\" object in a successful cycle_model response.","If cycling is impossible server-side, return a null payload instead of an object without \"model\".","Align protocol versions between client and server so the response schema matches.","Log the raw payload at the server to see why the model field is missing or malformed."],"exampleFix":"// before (server)\nreturn {\"thinkingLevel\": \"high\", \"isScoped\": false}\n// after\nreturn {\"model\": {\"id\": \"gpt-5\", \"provider\": \"openai\"}, \"thinkingLevel\": \"high\", \"isScoped\": false}","handlingStrategy":"validation","validationCode":"if payload is not None and (payload.get(\"model\") is None or not isinstance(payload.get(\"model\"), dict)):\n    raise TypeError(\"cycle_model payload missing valid 'model' object\")","typeGuard":"def has_model(payload: dict | None) -> bool:\n    return payload is not None and isinstance(payload.get(\"model\"), dict)","tryCatchPattern":"try:\n    result = parse_model_cycle_result(payload)\nexcept ValueError as exc:\n    raise ProtocolError(f\"cycle_model bad response: {payload!r}\") from exc","preventionTips":["Keep client and server protocol schemas in sync (shared schema/contract tests).","Return a null payload from the server when cycling is impossible rather than a bare object.","Log raw RPC payloads on parse failure to speed diagnosis."],"tags":["python","rpc","protocol","schema-validation"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}