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

  1. Add an 'efforts' list (e.g. ["minimal","low","medium","high"]) to the thinking object
  2. 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
  3. Fix the server/model-catalog source emitting the incomplete thinking object
  4. 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

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


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/aca5de17d1365078. Report an issue: GitHub.