can1357/oh-my-pi · error · ValueError
assistantMessageEvent.content must be a string
Error message
assistantMessageEvent.content must be a string
What it means
End events must carry the finalized block content as a string. The parser raises this error when the 'content' key is absent or is not a string, so AssistantTextEndEvent/AssistantThinkingEndEvent always expose the complete text.
Source
Thrown at python/omp-rpc/src/omp_rpc/protocol.py:410
return AssistantToolCallDeltaEvent(
type="toolcall_delta",
contentIndex=content_index,
delta=delta,
partial=partial,
)
if event_type in {"text_end", "thinking_end"}:
partial = _parse_assistant_message(
_clone_json_object(
payload.get("partial"), field="assistantMessageEvent.partial"
),
field="assistantMessageEvent.partial",
)
content_index = _optional_int(payload, "contentIndex")
content = _optional_str(payload, "content")
if content_index is None:
raise ValueError("assistantMessageEvent.contentIndex must be an integer")
if content is None:
raise ValueError("assistantMessageEvent.content must be a string")
if event_type == "text_end":
return AssistantTextEndEvent(
type="text_end",
contentIndex=content_index,
content=content,
partial=partial,
)
return AssistantThinkingEndEvent(
type="thinking_end",
contentIndex=content_index,
content=content,
partial=partial,
)
if event_type == "toolcall_end":
partial = _parse_assistant_message(
_clone_json_object(
payload.get("partial"), field="assistantMessageEvent.partial"
),View on GitHub (pinned to 9690622007)
Solutions
- Include the full accumulated content string in end events
- Fix the emitter to accumulate deltas and populate content on end
- If the full content is unavailable, accumulate text_delta fragments client-side and synthesize a valid event
- Upgrade mismatched protocol implementations
Example fix
// before
{"type": "text_end", "contentIndex": 0}
// after
{"type": "text_end", "contentIndex": 0, "content": "full text"} Defensive patterns
Strategy: validation
Validate before calling
if event.get("type") in {"text_end", "thinking_end"} and not isinstance(event.get("content"), str):
raise ValueError("end event missing string content") Type guard
def has_string_content(e: dict) -> bool:
return isinstance(e.get("content"), str) Try / catch
try:
event = parse_assistant_message_event(payload)
except ValueError as e:
logger.warning("end event without content: %s", e)
event = None # optionally reconstruct from accumulated deltas Prevention
- Accumulate deltas server-side and include full content on end events
- Never omit 'content'; use "" when empty
- Round-trip test synthesized events through the parser
When it happens
Trigger: text_end/thinking_end notification missing 'content', or with content as an object/array/null; an emitter that only sends deltas and skips the final content accumulation.
Common situations: Custom bridges that emit end markers without accumulating full text; providers whose end event uses a differently named field; protocol version mismatch.
Understand the failure class
Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.
Related errors
- assistantMessageEvent.contentIndex must be an integer
- assistantMessageEvent.delta must be a string
- Received text_delta for non-text content
- Received text_end for non-text content
- Received thinking_delta for non-thinking content
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/33411a5db4a20e28.
Report an issue: GitHub.