You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Custom OpenAI-compatible provider: "Expected 'function.name' to be a string" on streaming tool call chunks #26412
When using a custom OpenAI-compatible provider with a vLLM backend, any tool call (Read, Edit, Bash…) fails immediately with:
Expected 'function.name' to be a string.
Root cause (confirmed via curl)
The OpenAI streaming spec sends function.name only in the first delta chunk; subsequent chunks carry "name": null. This is correct per the OpenAI API reference. OpenCode's AI SDK validates each chunk independently and rejects null as invalid.
Raw streaming response from the backend (reproduced with curl):
# Chunk 1 — name is a string ✓
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"name":"read_file","arguments":""}}]}}]}
# Chunk 2 — name is null per OpenAI spec → OpenCode crashes here
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"name":null,"arguments":"{\"path\": \"test"}}]}}]}
# Chunk 3
data: {"choices":[{"delta":{"tool_calls":[{"index":0,"function":{"name":null,"arguments":".py\""}}]}}]}
Adding "compatibility": "compatible" to the provider options has no effect.
Steps to reproduce
Configure a custom provider with npm: "@ai-sdk/openai-compatible" pointing to any OpenAI-compatible backend that streams tool calls (vLLM, LM Studio, llama.cpp server, etc.)
Ask the model to read or edit a file
Error is thrown on the second streaming chunk
Expected behavior
function.name: null in non-first chunks should be accepted — the client should accumulate the name from the first chunk, as the OpenAI Python SDK and most other clients do.
Workaround
None found via provider options. Using Anthropic native providers is unaffected (different code path).
Reacted by eddiez9, Jay, ilya, kennethkwok-healthera and Sage Grigull
Yeah, qwen3_coder presents lots of other tool errors as the parse misses the call and passes it through as text. This makes long running sessions fail as the tool call doesn't run and thus doesn't trigger a response for the agent.
Okay, super simple workaround to this: instead of using OpenAI compatible provider use an Anthropic specific one. For vLLM, which supports both, this worked great.
@jlongster this is easily duplicated on DeepInfra (XiaomiMiMo/MiMo-V2.5)
OpenRouter looks like it alters the LLM result to prevent this error, there is many models which would trigger this depending on their configuration and my assumption is that this has a wide impact.
Okay, super simple workaround to this: instead of using OpenAI compatible provider use an Anthropic specific one. For vLLM, which supports both, this worked great.
Using the Anthropic provider package results in failing tool calls :-(
Edit: we use liteLLM in front of vLLM
Another workaround is to put a local gateway between OpenCode and the vLLM
endpoint. The gateway can accumulate the tool call across chunks instead of
passing each function.name: null through to OpenCode.
In Swobu, create a workspace such as opencode with one
route:
Route
Backend model
Backend URL
Protocol
local-tools
your vLLM model
your vLLM /v1 URL
Streaming Chat Completions
Then point OpenCode's OpenAI-compatible provider at the workspace:
I replayed the stream from this issue through that path. Swobu retained read_file from the first chunk, combined the later argument chunks into {"path":"test.py"}, and returned a tool-call stream with no function.name: null values.
The target protocol must be Streaming Chat Completions. This works around
the chunk-validation problem; it does not fix OpenCode or change the vLLM
parser. The model and backend still need to produce an otherwise valid tool
call.
Disclosure: I maintain Swobu. If you try this, I would welcome hearing whether
it works with your OpenCode/vLLM setup. For a Swobu-specific failure, please
share the error and stream shape at github.com/swobuforge/swobu, and I will
help investigate.
Still reproducible on 1.18.34. Root cause confirmed by grepping published tarballs: the throw string Expected 'function.name' ships in @ai-sdk/openai-compatible up to 2.0.7 and is gone from 3.0.0 onward (vercel/ai#18440 / PR #18445 fixed it upstream) — but opencode's compiled binary still bundles a pre-3.0.0 copy, so every closed tracker reads "fixed/not-ours" while users keep hitting it.
Filed with evidence + a deterministic synthetic-SSE reproduction (no real API key needed): #52462
Activity
github-actions commentedon May 8, 2026
This issue might be a duplicate of existing issues. Please check:
@ai-sdk/openai-compatibleperforms strict Zod validation on every streaming chunk and rejects fields that are null/missing in non-first chunks (in that caseindex, herefunction.name). The fix direction (upgrading or patching the SDK to use.nullish()) is the same.If you believe this is a distinct issue, please clarify how it differs from #17902.
tmaiaroto commentedon Jun 7, 2026
Still an issue. Can't use local models like Qwen3.6-35B-A3B for example.
Bastiendsp commentedon Jun 9, 2026
On your vLLM, use
qwen3_coderinstead ofqwen3_xmlparser. It should fix your problemtmaiaroto commentedon Jun 10, 2026
That's a legacy parser though,
qwen3_xmlis the current for newer models. That breaks things worse.tedivm commentedon Jun 14, 2026
Yeah, qwen3_coder presents lots of other tool errors as the parse misses the call and passes it through as text. This makes long running sessions fail as the tool call doesn't run and thus doesn't trigger a response for the agent.
tedivm commentedon Jun 14, 2026
Okay, super simple workaround to this: instead of using OpenAI compatible provider use an Anthropic specific one. For vLLM, which supports both, this worked great.
fix(llm): allow null function.name in streaming tool calls for OpenAI…
charlesverge commentedon Jun 17, 2026
@jlongster this is easily duplicated on DeepInfra (XiaomiMiMo/MiMo-V2.5)
OpenRouter looks like it alters the LLM result to prevent this error, there is many models which would trigger this depending on their configuration and my assumption is that this has a wide impact.
hcguersoy-cg commentedon Jun 30, 2026
Using the Anthropic provider package results in failing tool calls :-(
Edit: we use liteLLM in front of vLLM
hcguersoy-cg commentedon Jul 3, 2026
I wrote a little Python 'proxy' for OpenCode, which replaces
nullvalues infunction.namewith an empty string.It works in my environment with liteLLM and OpenCode 1.17.10 on macOS.
You can find it in my Gist: https://gist.github.com/hcguersoy-cg/2303d3807700d25bb7a6f7e9f3d7bbfb
Feedback / improvement suggestions are welcome.
metrofun commentedon Jul 31, 2026
Another workaround is to put a local gateway between OpenCode and the vLLM
endpoint. The gateway can accumulate the tool call across chunks instead of
passing each
function.name: nullthrough to OpenCode.In Swobu, create a workspace such as
opencodewith oneroute:
local-tools/v1URLThen point OpenCode's OpenAI-compatible provider at the workspace:
{ "$schema": "https://opencode.ai/config.json", "model": "swobu/local-tools", "provider": { "swobu": { "npm": "@ai-sdk/openai-compatible", "name": "Swobu", "options": { "baseURL": "http://127.0.0.1:7926/c/opencode/v1" }, "models": { "local-tools": { "name": "Local tools" } } } } }I replayed the stream from this issue through that path. Swobu retained
read_filefrom the first chunk, combined the later argument chunks into{"path":"test.py"}, and returned a tool-call stream with nofunction.name: nullvalues.The target protocol must be Streaming Chat Completions. This works around
the chunk-validation problem; it does not fix OpenCode or change the vLLM
parser. The model and backend still need to produce an otherwise valid tool
call.
Disclosure: I maintain Swobu. If you try this, I would welcome hearing whether
it works with your OpenCode/vLLM setup. For a Swobu-specific failure, please
share the error and stream shape at
github.com/swobuforge/swobu, and I will
help investigate.
github-actions commentedon Sep 30, 2026
To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.
nazerim commentedon Oct 1, 2026
Still reproducible on 1.18.34. Root cause confirmed by grepping published tarballs: the throw string
Expected 'function.name'ships in@ai-sdk/openai-compatibleup to 2.0.7 and is gone from 3.0.0 onward (vercel/ai#18440 / PR #18445 fixed it upstream) — but opencode's compiled binary still bundles a pre-3.0.0 copy, so every closed tracker reads "fixed/not-ours" while users keep hitting it.Filed with evidence + a deterministic synthetic-SSE reproduction (no real API key needed): #52462
Interim fix (MIT, plugin-only, no core changes): https://github.com/nazerim/toolcall-guard — repairs/buffers malformed
tool_callsdeltas at the fetch layer, scrubs replayed ChatML tokens from outbound history (they re-arm the provider's parser every turn), and auto-continues turns the provider silently truncates at a cleanfinish_reason:"stop".