Skip to content

[Bug] Claude Code DeepSeek route fails on built-in Artifact tool schema #5658

Description

@ChrisSpotta

Client or integration

Claude Code

Provider or upstream service

deepseek (route: ocx-deepseek-flash → requested model deepseek/deepseek-flash)

OpenCodex version

2.60.0

Environment

  • OS: Debian GNU/Linux 12 (bookworm)
  • Architecture: x86_64
  • OpenCodex: 2.60.0
  • Claude Code: 2.1.263
  • Node: v22.22.2
  • OpenCodex multi-agent mode: v1

Endpoint or capability

Tool calls / function-calling schema — specifically the JSON Schema for Claude Code's built-in Artifact tool, sent as part of the tool-definition set on every request through this route.

Current behaviour

Every tested request through the ocx-deepseek-flash route failed with an HTTP 400 before any model output is produced. The upstream provider rejects the JSON Schema for Claude Code's built-in Artifact tool. This reproduces on a plain bounded request (no attempt to invoke the tool — the rejection happens during request/schema validation, before any tool call is made).

Expected behaviour

The route should complete successfully like the other tested OpenCodex Claude Code routes. In the same session, under the identical launch mode (ocx-code, Claude.ai MCP disabled, strict MCP configuration), the following routes all returned HTTP 200 and the exact requested output: ocx-qwen3-8-27b, ocx-minimax-m3, ocx-gpt-5-6-sol, ocx-gpt-6-astra. This is a concrete client-observed requirement (working sibling routes in the same harness), not a specific published DeepSeek schema specification (see "Upstream documentation" below).

Minimal redacted request or reproduction

  1. Launch Claude Code in ocx-code mode with Claude.ai MCP disabled, strict MCP configuration. The local ocx-code shortcut expands to:

    ENABLE_CLAUDEAI_MCP_SERVERS=false \
    ocx claude --model sonnet --strict-mcp-config
  2. Invoke the ocx-deepseek-flash subagent with any bounded task (tested: a no-tool, no-file task requesting a fixed sentinel string in response).

  3. Observe the call fail before any response is produced.

Reproduced in two separate runs:

  • Original verification run — run ID ocx-verify-20260922T150542Z-be2d9d6c.
  • Isolation test with Artifact explicitly added to the subagent's disallowedTools front-matter field — run ID deepseek-noartifact-20260922T152244Z-28920a04.

No request body was captured or is available to redact/attach beyond the ocx logs --json metadata below; the client (Claude Code) constructs the tool schema set internally.

Actual response or error

Invalid schema for function 'Artifact': {"pattern":"^[^\u0000]*$","maxLength":1024,"minLength":1,"type":"string"} is not valid under any of the schemas listed in the 'anyOf' keyword

HTTP status 400. Observed identically, verbatim, in both runs. Model sent to the API: claude-ocx-deepseek--deepseek-flash.

Correlated ocx logs --json metadata (non-secret fields only):

Test requestedModel provider resolvedModel status durationMs
Original run deepseek/deepseek-flash deepseek null 400 593
Isolation run (disallowedTools: Artifact) deepseek/deepseek-flash deepseek null 400 641
Other 4 routes, same session (for contrast) qwen3.8-27b / MiniMax-M3 / gpt-5.6-sol / gpt-6-astra qwen-local / minimax / openai / openai (each matched) 200 1.5s–25.9s

Upstream documentation

No public DeepSeek specification describing its function-calling JSON-Schema validator's accepted keyword set (e.g. its handling of anyOf) was located or consulted for this report; stating that clearly per the template's own allowance. Two independent third-party projects have documented closely related failures of the same Claude Code Artifact tool schema against other providers/proxies (see "Related reports" below) — those reports may be the closest available prior art, though they describe a pattern/regex rejection rather than the anyOf rejection observed here.

Suggested mapping or implementation notes

Any of the following would address this:

  • Omit genuinely disallowed tools from the request sent upstream before request construction, rather than after (or in addition to) wherever filtering currently occurs — the isolation test showed disallowedTools: ["Artifact"] at the agent-definition level does not currently prevent the tool's schema from reaching the DeepSeek request.
  • Sanitise or relax JSON Schema constructs in the Artifact tool definition that this provider's function-calling validator does not accept (here, a string sub-schema nested under anyOf).
  • Provide a provider capability switch/flag that suppresses unsupported built-in tools (such as Artifact) for routes known not to support their schema.

Precedent for the schema-sanitisation approach exists in unrelated projects that hit the same Claude Code Artifact tool schema against other backends (see below) — one of them (CLIProxyAPI) shipped a fix by stripping/sanitising unsupported regex constructs before forwarding the schema.

Related reports (corroborating evidence, not OpenCodex duplicates)

These are different projects, different proxies, and — as far as could be determined — a different specific schema keyword than the one observed here, so they are not duplicates of this issue. They are included because they independently confirm that Claude Code's built-in Artifact tool schema is a recurring source of incompatibility with third-party providers'/proxies' function-calling JSON-Schema validators:

  • QuantumNous/new-api issue #7303 — reports DeepSeek's gateway rejecting a pattern regex (using Unicode property classes and a negative lookahead) inside Claude Code's Artifact tool schema, with the error Invalid schema for function 'T': "..." is not a "regex". Closed as "not planned" (filed as an opt-in feature request, not accepted as scoped).
  • router-for-me/CLIProxyAPI issue feat(gui): autosave featured subagent roster edits #5644 — reports the same Artifact tool's pattern field (Unicode property classes + lookahead) being rejected by strict JSON Schema validators when translating Claude→OpenAI-compatible requests, with error text Invalid schema for function 'Artifact': ... is not a 'regex'. Fixed via PR devlog: close the 2.64 release round #5677 (stripping/sanitising the unsupported regex constructs before translation).

Note the distinction: those two reports describe a pattern-is-not-a-valid-regex rejection on a different Artifact field (using \p{Cc}-style Unicode property classes and a negative lookahead). The failure recorded in this draft is an anyOf schema-composition rejection on a simpler pattern (^[^\u0000]*$). Both are plausibly part of the same broader class of problem — Claude Code's Artifact tool schema using JSON Schema constructs that not every provider's function-calling validator accepts — but this report does not claim they share an identical root cause.

Additional context: attempted mitigation

Added disallowedTools: ["Artifact"] to the ocx-deepseek-flash subagent's front matter as a temporary, controlled test (file backed up before the change and restored byte-for-byte afterward; original and restored SHA-256 matched exactly). The mitigation did not change the outcome — the identical schema rejection occurred, with the same status (400), same null resolvedModel, and the same error text. This narrows the finding (agent-level tool exclusion alone does not fix it) without establishing which internal component is responsible.

Reported context, not independently verified in this diagnostic session: deepseek-flash has reportedly completed successfully via the Codex-native subagent route, which — if accurate — would suggest the fault is specific to the Claude Code request/tool-schema construction path rather than to the DeepSeek model or provider generally. This report does not claim which internal component is definitely responsible.

Duplicate search

Searched lidge-jun/opencodex issues (read-only, no issue created/commented) for: Artifact, DeepSeek, anyOf, Invalid schema for function, and Claude Code DeepSeek schema-style terms. No exact or near-duplicate issue was found — no open or closed issue in that tracker mentions the Artifact tool, an anyOf schema rejection, or this exact error text.

One issue in the same tracker is topically adjacent but not a duplicate: #5421, "DeepSeek thinking mode HTTP 400 (reasoning_text must be passed back) when a routed subagent thinking turn lost its reasoning text" — same provider (deepseek) and same HTTP status (400), but a distinct root cause (a reasoning-text passback requirement, not a tool-schema/anyOf rejection).

This search was not exhaustive (a fixed set of targeted queries against the tracker's search UI); it should not be treated as a certainty that no related issue exists.

Security statement

No API keys, OAuth tokens, credentials, or other secret/environment material are included anywhere in this report. The metadata fields actually displayed above (requestedModel, provider, resolvedModel, status, durationMs) are non-secret request metadata from ocx logs --json, and the error text is a schema-validation message containing no credential data.

Checks (per template)

  • Searched existing provider and compatibility issues (see "Duplicate search" above; not claimed exhaustive).
  • The request and response were redacted (no request bodies were available to redact beyond the sanitised error text and log metadata above; nothing further was withheld).
  • The expected behaviour is based on a concrete client requirement (four sibling routes succeeding in the same session, same launch mode) rather than a published upstream specification, since no such specification was located (see "Upstream documentation").

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: P2Medium: provider/client-specific bug with a workaround, bounded enhancement tied to a tracked issue,providerProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reportstoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions