can1357/oh-my-pi · error · ValueError

{field} must be one of: {expected}

Error message

{field} must be one of: {expected}

What it means

`_require_literal` enforces enum-like string fields: the value must be a `str` and a member of the allowed frozenset, otherwise the error lists the accepted values (sorted). It backs typed literals such as message roles, thinking levels/efforts, todo statuses, stop reasons, and session states used by `_parse_agent_message`, `parse_assistant_message_event`, `_parse_thinking_config`, `parse_todo_item`, and `parse_session_state`.

Source

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

    if values is None:
        return None
    if not isinstance(values, list):
        raise ValueError(f"{field} must be a list")
    return tuple(_clone_json_object(item, field=f"{field}[]") for item in values)


def _clone_json_objects(values: object, *, field: str) -> tuple[JsonObject, ...]:
    if values is None:
        return ()
    if not isinstance(values, list):
        raise ValueError(f"{field} must be a list")
    return tuple(_clone_json_object(item, field=f"{field}[]") for item in values)


def _require_literal(value: object, allowed: frozenset[str], *, field: str) -> str:
    if not isinstance(value, str) or value not in allowed:
        expected = ", ".join(sorted(allowed))
        raise ValueError(f"{field} must be one of: {expected}")
    return value


def _optional_literal(
    value: object, allowed: frozenset[str], *, field: str
) -> str | None:
    if value is None:
        return None
    return _require_literal(value, allowed, field=field)


def _require_str(payload: JsonObject, field: str) -> str:
    value = payload.get(field)
    if not isinstance(value, str):
        raise ValueError(f"{field} must be a string")
    return value

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the allowed values listed in the error message and change your payload to exactly one of them (case-sensitive).
  2. If using an Enum, pass `my_enum.value` rather than the enum instance so it arrives as a plain str.
  3. Cross-check your field values against the Literal type aliases at the top of omp_rpc/protocol.py (e.g. Effort, ThinkingLevel, TodoStatus) for the version you are running.
  4. Check for client/daemon version drift: renamed literal values require updating the sender to the new vocabulary.

Example fix

// before
parse_todo_item({"id": "1", "content": "ship", "status": "done"})
// ValueError: status must be one of: abandoned, blocked, completed, in_progress, pending

// after
parse_todo_item({"id": "1", "content": "ship", "status": "completed"})
Defensive patterns

Strategy: validation

Validate before calling

_EFFORT = {"minimal", "low", "medium", "high", "xhigh", "max"}
_TODO_STATUS = {"pending", "in_progress", "completed", "abandoned", "blocked"}
_ROLES = {"user", "developer", "assistant", "toolResult", "bashExecution",
          "pythonExecution", "custom", "hookMessage", "branchSummary",
          "compactionSummary", "fileMention"}

assert value in _EFFORT, f"effort {value!r} not in {sorted(_EFFORT)}"
assert status in _TODO_STATUS, f"status {status!r} not in {sorted(_TODO_STATUS)}"
assert role in _ROLES, f"role {role!r} not in {sorted(_ROLES)}"

Type guard

from typing import TypeGuard
def is_allowed_literal(value: object, allowed: frozenset[str]) -> TypeGuard[str]:
    return isinstance(value, str) and value in allowed

Try / catch

try:
    item = parse_todo_item(raw)
except ValueError as exc:
    if "must be one of" in str(exc):
        allowed = str(exc).split(": ")[-1].split(", ")
        logger.error("invalid literal %r for %s; allowed: %s",
                     raw.get(field), field, allowed)
        raise TypeError(exc) from None
    raise

Prevention

When it happens

Trigger: Supplying an unrecognized or non-string value for a Literal field, e.g. role 'system' (not in the accepted roles set), effort 'ultra' instead of one of minimal|low|medium|high|xhigh|max, todo status 'done' instead of 'completed', or passing an enum member object instead of its `.value` string.

Common situations: Using a role or status name from a different API version or another library's enum; passing Python `Enum` instances instead of plain strings; typos or case mistakes ('High' vs 'high'); a protocol update that renamed a literal value while your client still sends the old one.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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