Skip to content

Custom OpenAI-compatible provider: "Expected 'function.name' to be a string" on streaming tool call chunks #26412

Closed as not planned

Description

@mazingerzzz

Environment

  • OpenCode: 1.14.41
  • Provider: @ai-sdk/openai-compatible (custom, vLLM backend)
  • OS: Linux (Debian)

Description

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

  1. 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.)
  2. Ask the model to read or edit a file
  3. 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).

Activity

  1. github-actions commented on May 8, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of existing issues. Please check:

    If you believe this is a distinct issue, please clarify how it differs from #17902.

  2. tmaiaroto commented on Jun 7, 2026

    @tmaiaroto

    Still an issue. Can't use local models like Qwen3.6-35B-A3B for example.

  3. Bastiendsp commented on Jun 9, 2026

    @Bastiendsp

    On your vLLM, use qwen3_coder instead of qwen3_xml parser. It should fix your problem

  4. tmaiaroto commented on Jun 10, 2026

    @tmaiaroto

    That's a legacy parser though, qwen3_xml is the current for newer models. That breaks things worse.

  5. tedivm commented on Jun 14, 2026

    @tedivm

    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.

  6. tedivm commented on Jun 14, 2026

    @tedivm

    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.

  7. added a commit that references this issue on Jun 17, 2026
    96dda48
  8. charlesverge commented on Jun 17, 2026

    @charlesverge

    @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.

  9. hcguersoy-cg commented on Jun 30, 2026

    @hcguersoy-cg

    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

  10. hcguersoy-cg commented on Jul 3, 2026

    @hcguersoy-cg

    I wrote a little Python 'proxy' for OpenCode, which replaces null values in function.name with 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.

  11. metrofun commented on Jul 31, 2026

    @metrofun

    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:

    {
      "$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_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.

  12. github-actions commented on Sep 30, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

  13. nazerim commented on Oct 1, 2026

    @nazerim

    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

    Interim fix (MIT, plugin-only, no core changes): https://github.com/nazerim/toolcall-guard — repairs/buffers malformed tool_calls deltas 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 clean finish_reason:"stop".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions