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
- Serialize the thinking payload to a string (json.dumps / join)
- 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
- Always stringify thinking payloads (json.dumps for traces)
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
- assistant reasoning_content must be a string for Inkling ren
- message content must be a string or a sequence of parts
- content part must be mapping, got {type(part).__name__}
- Inkling reasoning_effort must be a number
- expected mapping, got {type(value).__name__}
AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28).
Data as JSON: /api/errors/8b7d4e7382e7b6e8.
Report an issue: GitHub.