sgl-project/sglang · error · TypeError

message content must be a string or a sequence of parts

Error message

message content must be a string or a sequence of parts

What it means

_iter_render_parts accepts message content that is either a string or a non-bytes Sequence of parts. Passing bytes/bytearray, a dict, a number, or None-like non-string scalar raises TypeError.

Source

Thrown at python/sglang/srt/parser/inkling_renderer.py:224

    elif kind == "invoke_tool_json":
        input_ids.append(tokenizer.encode_special(CONTENT_INVOKE_TOOL_JSON))
        input_ids.extend(tokenizer.encode_text(text))
    else:
        raise ValueError(f"unsupported Inkling render part kind: {kind!r}")

    input_ids.append(tokenizer.encode_special(END_MESSAGE))


def _iter_render_parts(content: Any):
    """Yield ordered ``(kind, text)`` pairs from message content."""
    if content is None:
        return
    if isinstance(content, str):
        if content:
            yield ("text", content)
        return
    if not isinstance(content, Sequence) or isinstance(content, (bytes, bytearray)):
        raise TypeError("message content must be a string or a sequence of parts")
    for part in content:
        if isinstance(part, str):
            yield ("text", part)
            continue
        if not isinstance(part, Mapping):
            raise TypeError(f"content part must be mapping, got {type(part).__name__}")
        ptype = part.get("type")
        if ptype in (None, "text", "input_text"):
            text = part.get("text", "")
            yield ("text", text if isinstance(text, str) else "")
        elif ptype in ("thinking", "reasoning"):
            text = part.get("thinking")
            if text is None:
                text = part.get("text", "")
            if not isinstance(text, str):
                raise TypeError("Inkling thinking part payload must be a string")
            yield ("thinking", text)
        elif ptype in _IMAGE_PART_TYPES:

View on GitHub (pinned to 0132848349)

Solutions

  1. Decode bytes to str and json.loads if it is a serialized message list
  2. Pass content as a string or a list of part dicts
  3. Wrap a single part dict in a list

Example fix

# before
msg["content"] = b'[{"type":"text","text":"hi"}]'
# after
msg["content"] = json.loads(msg["content"].decode())  # or just "hi"
Defensive patterns

Strategy: type-guard

Validate before calling

from collections.abc import Sequence, Mapping, ByteString
for m in messages:
    c = m.get("content", "")
    assert isinstance(c, str) or (isinstance(c, Sequence) and not isinstance(c, ByteString)), type(c)

Type guard

def content_ok(c):
    return isinstance(c, str) or (isinstance(c, Sequence) and not isinstance(c, (bytes, bytearray)))

Prevention

When it happens

Trigger: Passing message.content as bytes (e.g. a JSON-encoded payload not decoded), a dict, or an int in an Inkling-rendered chat request.

Common situations: Programmatic clients that forget json.loads on serialized messages, or that pass a single mapping as content instead of a list of mappings.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/542ef28fc213569d. Report an issue: GitHub.