{"record":{"id":"07dd31f98c19211c","repo":"sgl-project/sglang","slug":"expected-mapping-got-type-value-name","errorCode":null,"errorMessage":"expected mapping, got {type(value).__name__}","messagePattern":"expected mapping, got (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"python/sglang/srt/parser/inkling_renderer.py","lineNumber":277,"sourceCode":"\n\ndef _expect_role(message: Mapping[str, Any]) -> str:\n    role = message.get(\"role\")\n    if role not in ROLE_MESSAGE_TOKENS:\n        raise ValueError(\n            f\"unsupported Inkling message role {role!r}; expected one of {sorted(ROLE_MESSAGE_TOKENS)}\"\n        )\n    return str(role)\n\n\ndef _as_mapping(value: Any) -> Mapping[str, Any]:\n    if isinstance(value, Mapping):\n        return value\n    if hasattr(value, \"model_dump\"):\n        dumped = value.model_dump()\n        if isinstance(dumped, Mapping):\n            return dumped\n    raise TypeError(f\"expected mapping, got {type(value).__name__}\")\n\n\ndef _canonical_json(value: Any) -> str:\n    return json.dumps(\n        _sort_json(value),\n        ensure_ascii=False,\n        allow_nan=False,\n        separators=(\",\", \":\"),\n    )\n\n\ndef _sort_json(value: Any) -> Any:\n    if isinstance(value, Mapping):\n        return {str(key): _sort_json(value[key]) for key in sorted(value)}\n    if isinstance(value, Sequence) and not isinstance(value, (str, bytes, bytearray)):\n        return [_sort_json(item) for item in value]\n    return value\n","sourceCodeStart":259,"sourceCodeEnd":295,"githubUrl":"https://github.com/sgl-project/sglang/blob/0132848349585cfe6aae51c4941cbae872505f8a/python/sglang/srt/parser/inkling_renderer.py#L259-L295","documentation":"_as_mapping normalizes tool definitions, tool calls, and messages to a Mapping before rendering. It accepts a Mapping or any object with model_dump() returning a Mapping; anything else (str, int, list, None) raises TypeError.","triggerScenarios":"Passing a tool_call as a JSON string instead of a dict, e.g. {\"role\":\"assistant\",\"tool_calls\":[\"{\\\"name\\\":\\\"f\\\"}\"]}, or a tool definition as a list.","commonSituations":"Clients that json.dumps tool calls for transport and forget to parse them back; passing OpenAI SDK objects without model_dump support (older pydantic v1 style).","solutions":["Parse JSON strings back to dicts before sending: json.loads(s)","Pass plain dicts or pydantic v2 models (which support model_dump)","Wrap lists in a proper mapping structure"],"exampleFix":"# before\ntool_calls=[json.dumps({\"name\":\"f\",\"arguments\":{}})]\n# after\ntool_calls=[{\"name\":\"f\",\"arguments\":{}}]  # keep as dict","handlingStrategy":"type-guard","validationCode":"from collections.abc import Mapping\nfor m in messages:\n    for tc in m.get(\"tool_calls\") or []:\n        assert isinstance(tc, Mapping) or hasattr(tc, \"model_dump\"), type(tc)","typeGuard":"def tool_call_ok(tc): return isinstance(tc, Mapping) or hasattr(tc, \"model_dump\")","tryCatchPattern":null,"preventionTips":["Pass tool calls/tools as dicts, never JSON strings","Parse json.loads on any serialized tool payloads before sending"],"tags":["inkling","tool-calls","type-error"],"backgroundTag":"invalid-field-type","analyzedSha":"0132848349585cfe6aae51c4941cbae872505f8a","analyzedAt":"2026-08-28T05:10:05.995Z","schemaVersion":2},"datasetVersion":"2026-08-28T06:17:29.519Z"}