[BUG] malformed tool_reference content block injected into history breaks vLLM chat-template rendering (jinja2 TemplateError: "Unexpected item type in content")
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
When a tool (e.g. WebFetch) is invoked without its full schema loaded, the initial call fails with InputValidationError, and the recovery path (calling ToolSearch with select:<ToolName>) returns a tool result containing a content block of the form:
{"type": "tool_reference", "tool_name": "WebFetch"}
This block type is not part of the documented Anthropic Messages content-block schema (text, image, tool_use, tool_result, document, thinking, redacted_thinking). Once this block is written into conversation history, it gets replayed in subsequent API calls. Any downstream consumer of that history that strictly validates/renders content blocks against the standard schema will reject it — observed concretely as a jinja2.exceptions.TemplateError: Unexpected item type in content when the conversation was replayed through a self-hosted OpenAI/Anthropic-compatible endpoint (vLLM + transformers.apply_chat_template).
What Should Happen?
no error.
Error Messages/Logs
"{
"role": "user",
"content": "Help me create an issue for the mantainer. Analyze https://github.com/open-gsd/gsd-core/blob/next/CONTRIBUTING.md e create me an issue of this problem respecting their contribution rules",
"_tokens": 43
}"
"{
"role": "assistant",
"content": [
{
"type": "thinking",
"thinking": "The user wants me to analyze the CONTRIBUTING.md file and create an issue about the \"Bash is not defined\" error in Workflow scripts. I need to first fetch and read the CONTRIBUTING.md file to understand their issue template and contribution guidelines.\n",
"signature": "fda63472c0d345c79f517834a4cadeaf"
},
{
"type": "tool_use",
"id": "chatcmpl-tool-86344fd2554aad12",
"name": "WebFetch",
"input": {
"url": "https://raw.githubusercontent.com/open-gsd/gsd-core/next/CONTRIBUTING.md"
}
}
],
"_tokens": 130
}"
"{
"role": "user",
"content": [
{
"type": "tool_result",
"content": "InputValidationError: WebFetch failed due to the following issue:\nThe required parameter prompt is missing\n\nThis tool's schema was not sent to the API — it was not in the discovered-tool set derived from message history. Without the schema in your prompt, typed parameters (arrays, numbers, booleans) get emitted as strings and the client-side parser rejects them. Load the tool first: call ToolSearch with query \"select:WebFetch\", then retry this call. For reference, this tool's input schema is: {\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"type\":\"object\",\"properties\":{\"url\":{\"description\":\"The URL to fetch content from\",\"type\":\"string\",\"format\":\"uri\"},\"prompt\":{\"description\":\"The prompt to run on the fetched content\",\"type\":\"string\"}},\"required\":[\"url\",\"prompt\"],\"additionalProperties\":false}",
"is_error": true,
"tool_use_id": "chatcmpl-tool-86344fd2554aad12"
}
],
"_tokens": 228
}"
"{
"role": "assistant",
"content": [
{
"type": "thinking",
"thinking": "The WebFetch tool requires both 'url' and 'prompt' parameters, so I need to add a minimal prompt to complete the request.\n",
"signature": "7be44cfc06eb4070be23d2fdff3bbbf5"
},
{
"type": "tool_use",
"id": "chatcmpl-tool-988b385abf51fda0",
"name": "ToolSearch",
"input": {
"max_results": 1,
"query": "select:WebFetch"
}
}
],
"_tokens": 102
}"
"{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "chatcmpl-tool-988b385abf51fda0",
"content": [
{
"type": "tool_reference",
"tool_name": "WebFetch"
}
]
},
{
"type": "text",
"text": "Tool loaded.\n"
},
{
"type": "text",
"text": "try again please",
"cache_control": {
"type": "ephemeral"
}
}
],
"_tokens": 72
}"
Steps to Reproduce
- Configure Claude Code against an Anthropic-compatible endpoint (e.g. local vLLM).
- Trigger a tool call before its schema is fully loaded (observed with
WebFetchmissing the requiredpromptparam). - Observe the
ToolSearchrecovery flow inject atool_referenceblock into the tool_result content array. - Continue the conversation — the next request containing that history is rejected by the receiving server.
Claude Model
Other
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.210
Platform
Other
Operating System
Ubuntu/Debian Linux
Terminal/Shell
Other
Additional Information
This may be intentional internal protocol shape for Anthropic-hosted inference, but it's undocumented and breaks non-Anthropic-hosted or self-hosted endpoints that validate against the public Messages API content-block schema. Worth documenting tool_reference as an official block type, or ensuring it's never written into replayable history sent to third-party-compatible endpoints.