{"record":{"id":"aca5de17d1365078","repo":"can1357/oh-my-pi","slug":"model-thinking-efforts-must-be-a-list","errorCode":null,"errorMessage":"model.thinking.efforts must be a list","messagePattern":"model\\.thinking\\.efforts must be a list","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/protocol.py","lineNumber":1247,"sourceCode":"\ndef assistant_text(\n    message: AgentMessage, *, include_thinking: bool = False\n) -> str | None:\n    if message.get(\"role\") != \"assistant\":\n        return None\n    return message_text(message, include_thinking=include_thinking)\n\n\ndef assistant_text_with_thinking(message: AgentMessage) -> str | None:\n    return assistant_text(message, include_thinking=True)\n\n\ndef _parse_thinking_config(payload: object) -> ThinkingConfig | None:\n    if not isinstance(payload, dict):\n        return None\n    raw_efforts = payload.get(\"efforts\")\n    if not isinstance(raw_efforts, list):\n        raise ValueError(\"model.thinking.efforts must be a list\")\n    efforts: tuple[Effort, ...] = tuple(\n        cast(\n            Effort,\n            _require_literal(item, _EFFORT_VALUES, field=\"model.thinking.efforts[]\"),\n        )\n        for item in raw_efforts\n    )\n    return ThinkingConfig(\n        mode=_require_str(cast(JsonObject, payload), \"mode\"),\n        efforts=efforts,\n        default_level=cast(\n            Effort | None,\n            _optional_literal(\n                payload.get(\"defaultLevel\"),\n                _EFFORT_VALUES,\n                field=\"model.thinking.defaultLevel\",\n            ),\n        ),","sourceCodeStart":1229,"sourceCodeEnd":1265,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/protocol.py#L1229-L1265","documentation":"_parse_thinking_config validates a model's thinking configuration: if a payload dict is present, its 'efforts' key must be a list of valid effort literals. This error is raised when 'efforts' is missing or is not a list (a string, null, dict, etc.). The library throws because the typed ThinkingConfig requires a tuple of Effort values.","triggerScenarios":"Calling a parse/model-deserialization path (e.g. parsing a model descriptor or RPC response containing model.thinking) where thinking is a dict but efforts is absent, a string like \"low\", or any non-list; hand-written model metadata in config; server returning partial thinking info.","commonSituations":"Hand-editing model config files and omitting efforts; protocol/model-catalog version changes reshaping ThinkingConfig; building model dicts in tests without the efforts field.","solutions":["Add an 'efforts' list (e.g. [\"minimal\",\"low\",\"medium\",\"high\"]) to the thinking object","Omit the 'thinking' key entirely (or pass a non-dict) if the model has no thinking config — the parser returns None for non-dict payloads","Fix the server/model-catalog source emitting the incomplete thinking object","Update client and catalog versions so the ThinkingConfig schema matches"],"exampleFix":"// before\n{\"thinking\": {}}\n// after\n{\"thinking\": {\"efforts\": [\"low\", \"medium\", \"high\"]}}","handlingStrategy":"validation","validationCode":"thinking = model.get(\"thinking\")\nif isinstance(thinking, dict) and not isinstance(thinking.get(\"efforts\"), list):\n    raise ValueError(\"model.thinking.efforts must be a list of effort strings\")","typeGuard":"def has_valid_thinking(model: dict) -> bool:\n    t = model.get(\"thinking\")\n    return not isinstance(t, dict) or isinstance(t.get(\"efforts\"), list)","tryCatchPattern":"try:\n    thinking = _parse_thinking_config(raw)\nexcept ValueError as e:\n    logger.warning(\"invalid thinking config, ignoring: %s\", e)\n    thinking = None","preventionTips":["Omit the thinking key entirely for non-thinking models instead of sending an empty dict","Always provide efforts as a list of valid effort literals","Validate hand-edited model config against the schema before use"],"tags":["protocol","validation","model-config"],"backgroundTag":"schema-validation-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}