sgl-project/sglang · error · TypeError

Inkling thinking part payload must be a string

Error message

Inkling thinking part payload must be a string

What it means

For parts with type 'thinking' or 'reasoning', the payload is read from part['thinking'] (falling back to part['text']) and must be a string. A dict, number, list, or None-with-non-string-fallback raises TypeError.

Source

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

        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:
            yield ("image", "")
        elif ptype in _AUDIO_PART_TYPES:
            yield ("audio", "")
        else:
            raise ValueError(f"unsupported content part type: {ptype!r}")


def _format_reasoning_effort(reasoning_effort: float) -> str:
    if isinstance(reasoning_effort, bool) or not isinstance(
        reasoning_effort, (int, float)
    ):
        raise TypeError("Inkling reasoning_effort must be a number")
    value = float(reasoning_effort)
    if not math.isfinite(value) or not 0.0 <= value <= 0.99:
        raise ValueError("Inkling reasoning_effort must be finite and in [0.0, 0.99]")
    return f"{round(value, 2):g}"

View on GitHub (pinned to 0132848349)

Solutions

  1. Serialize the thinking payload to a string (json.dumps / join)
  2. Ensure either 'thinking' or 'text' key holds a str

Example fix

# before
{"type":"thinking","thinking":{"steps":["a"]}}
# after
{"type":"thinking","thinking":"a"}  # or json.dumps of the trace
Defensive patterns

Strategy: type-guard

Validate before calling

for m in messages:
    for p in (m.get("content") or []) if isinstance(m.get("content"), list) else []:
        if isinstance(p, dict) and p.get("type") in ("thinking","reasoning"):
            t = p.get("thinking", p.get("text"))
            assert t is None or isinstance(t, str), type(t)

Type guard

def thinking_payload_ok(p):
    if p.get("type") not in ("thinking","reasoning"): return True
    t = p.get("thinking") if p.get("thinking") is not None else p.get("text", "")
    return isinstance(t, str)

Prevention

When it happens

Trigger: Sending {"type":"thinking","thinking":{"steps":[...]}} or {"type":"reasoning","text":123}.

Common situations: Structured reasoning traces (step lists, JSON objects) placed directly into the thinking field.

Related errors


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