can1357/oh-my-pi · error · ValueError
model.thinking.efforts must be a list
Error message
model.thinking.efforts must be a list
What it means
_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.
Source
Thrown at python/omp-rpc/src/omp_rpc/protocol.py:1247
def assistant_text(
message: AgentMessage, *, include_thinking: bool = False
) -> str | None:
if message.get("role") != "assistant":
return None
return message_text(message, include_thinking=include_thinking)
def assistant_text_with_thinking(message: AgentMessage) -> str | None:
return assistant_text(message, include_thinking=True)
def _parse_thinking_config(payload: object) -> ThinkingConfig | None:
if not isinstance(payload, dict):
return None
raw_efforts = payload.get("efforts")
if not isinstance(raw_efforts, list):
raise ValueError("model.thinking.efforts must be a list")
efforts: tuple[Effort, ...] = tuple(
cast(
Effort,
_require_literal(item, _EFFORT_VALUES, field="model.thinking.efforts[]"),
)
for item in raw_efforts
)
return ThinkingConfig(
mode=_require_str(cast(JsonObject, payload), "mode"),
efforts=efforts,
default_level=cast(
Effort | None,
_optional_literal(
payload.get("defaultLevel"),
_EFFORT_VALUES,
field="model.thinking.defaultLevel",
),
),View on GitHub (pinned to 9690622007)
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
Example fix
// before
{"thinking": {}}
// after
{"thinking": {"efforts": ["low", "medium", "high"]}} Defensive patterns
Strategy: validation
Validate before calling
thinking = model.get("thinking")
if isinstance(thinking, dict) and not isinstance(thinking.get("efforts"), list):
raise ValueError("model.thinking.efforts must be a list of effort strings") Type guard
def has_valid_thinking(model: dict) -> bool:
t = model.get("thinking")
return not isinstance(t, dict) or isinstance(t.get("efforts"), list) Try / catch
try:
thinking = _parse_thinking_config(raw)
except ValueError as e:
logger.warning("invalid thinking config, ignoring: %s", e)
thinking = None Prevention
- 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
When it happens
Trigger: 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.
Common situations: Hand-editing model config files and omitting efforts; protocol/model-catalog version changes reshaping ThinkingConfig; building model dicts in tests without the efforts field.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- runInTerminal request did not include a command
- ${label} must be a string
- Unknown daemon state: ${state}
- daemon.readyPending must be an array
- response.ok must be a boolean
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/aca5de17d1365078.
Report an issue: GitHub.