can1357/oh-my-pi · error · ValueError

cycle_model response did not include a model

Error message

cycle_model response did not include a model

What it means

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.

Source

Thrown at python/omp-rpc/src/omp_rpc/protocol.py:1485

        summary=str(payload.get("summary", "")),
        short_summary=_optional_str(payload, "shortSummary"),
        first_kept_entry_id=str(payload.get("firstKeptEntryId", "")),
        tokens_before=int(payload.get("tokensBefore", 0)),
        details=_clone_json_value(payload.get("details"), field="compaction.details")
        if "details" in payload
        else None,
        preserve_data=_optional_json_object(
            payload.get("preserveData"), field="compaction.preserveData"
        ),
    )


def parse_model_cycle_result(payload: JsonObject | None) -> ModelCycleResult | None:
    if payload is None:
        return None
    model = parse_model_info(cast(JsonObject, payload.get("model")))
    if model is None:
        raise ValueError("cycle_model response did not include a model")
    return ModelCycleResult(
        model=model,
        thinking_level=cast(ThinkingLevel | None, payload.get("thinkingLevel")),
        is_scoped=bool(payload.get("isScoped", False)),
    )


def parse_thinking_level_cycle_result(
    payload: JsonObject | None,
) -> ThinkingLevelCycleResult | None:
    if payload is None or payload.get("level") is None:
        return None
    return ThinkingLevelCycleResult(level=cast(ThinkingLevel, payload["level"]))


def parse_cancellation_result(payload: JsonObject | None) -> CancellationResult:
    return CancellationResult(cancelled=bool((payload or {}).get("cancelled", False)))

View on GitHub (pinned to 9690622007)

Solutions

  1. Fix the server to always include a valid "model" object in a successful cycle_model response.
  2. If cycling is impossible server-side, return a null payload instead of an object without "model".
  3. Align protocol versions between client and server so the response schema matches.
  4. Log the raw payload at the server to see why the model field is missing or malformed.

Example fix

// before (server)
return {"thinkingLevel": "high", "isScoped": false}
// after
return {"model": {"id": "gpt-5", "provider": "openai"}, "thinkingLevel": "high", "isScoped": false}
Defensive patterns

Strategy: validation

Validate before calling

if payload is not None and (payload.get("model") is None or not isinstance(payload.get("model"), dict)):
    raise TypeError("cycle_model payload missing valid 'model' object")

Type guard

def has_model(payload: dict | None) -> bool:
    return payload is not None and isinstance(payload.get("model"), dict)

Try / catch

try:
    result = parse_model_cycle_result(payload)
except ValueError as exc:
    raise ProtocolError(f"cycle_model bad response: {payload!r}") from exc

Prevention

When it happens

Trigger: 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.

Common situations: 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.

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/4bf304b1d9a9f132. Report an issue: GitHub.