[BUG] Since 2.1.265 the Artifact tool's input_schema carries a `pattern` with Unicode property escapes (\p{Cc}); Anthropic-compatible third-party backends reject every interactive request with 400
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?
Interactive Claude Code sessions with ANTHROPIC_BASE_URL pointed at an Anthropic-compatible third-party backend (Z.AI GLM, via a local proxy; reproduced with plain curl against the backend too) fail on every turn with HTTP 400. claude -p against the same backend works.
Bisecting the two captured request bodies shows the trigger is the tools array: interactive mode includes the built-in Artifact tool, and since 2.1.265 the field property of its input_schema carries this pattern:
^(?!__.*__$)[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}"\\./[\]]{1,200}$
Removing that single pattern makes the identical request succeed. The other five patterns in the same schema are accepted, so the backend's problem is specifically the Unicode property escapes (\p{...}). It is the only pattern in Claude Code's whole tool set that uses them.
2.1.263 and earlier send the Artifact tool without that pattern and work. So every user of an Anthropic-compatible backend lost interactive Claude Code on upgrade to 2.1.265, while long-running older sessions kept working, which made this hard to attribute.
I know the backend is at fault for not accepting valid ECMA-262 syntax (reported to them separately), but Claude Code sends this schema to any base URL, and one non-portable pattern in one property breaks the whole product on third-party backends.
What Should Happen?
Either of:
- an ASCII-only pattern for
Artifact.input_schema.properties.field(the intent, "no control characters, quotes, backslashes, dots, slashes or brackets, not__x__", can be expressed without\p{...}), or - omit the
Artifacttool from the request when the base URL is not Anthropic's / the artifact capability is unavailable.
Interactive sessions should then behave like -p does today against these backends.
Error Messages/Logs
API Error: 400 [glm/glm-5.3] [400]: {"type":"error","error":{"type":"invalid_request_error","code":"1210","message":"[1210][Invalid API parameter, please check the documentation.][202609090759179161046158a5442f]"},"request_id":"202609090759179161046158a5442f"} (reset after 30s)
Steps to Reproduce
- Point Claude Code at an Anthropic-compatible backend whose schema validator does not support
\p{...}(Z.AI'shttps://api.z.ai/api/anthropicdoes not), e.g. in settings.json:
``json``
{"env":{"ANTHROPIC_BASE_URL":"https://api.z.ai/api/anthropic","ANTHROPIC_AUTH_TOKEN":"<key>","ANTHROPIC_DEFAULT_OPUS_MODEL":"glm-5.3"},"model":"opus"}
- Start
claude(interactive) with 2.1.265 or 2.1.266 and send any prompt: 400 / 1210 on every turn. - Run
claude -p "Say OK"with the same settings: works (print mode omits the Artifact tool). - Start the same interactive session with 2.1.263: works (the Artifact tool is sent, but without the
fieldpattern). - Capture the interactive request body (any logging proxy), replay it with the Artifact tool's
patternkeywords stripped: 200. Replay it with only thefieldpattern removed: 200. Keep only that pattern and drop the other five: 400.
Standalone repro without Claude Code, showing the backend rejects exactly this construct:
curl -s https://api.z.ai/api/anthropic/v1/messages -H 'content-type: application/json' -H 'anthropic-version: 2023-06-01' -H 'x-api-key: <KEY>' \
-d '{"model":"glm-5.3","max_tokens":32,"messages":[{"role":"user","content":"Say OK"}],"tools":[{"name":"probe","description":"probe","input_schema":{"type":"object","properties":{"field":{"type":"string","pattern":"^[^\\p{Cc}]{1,200}$"}}}}]}'
returns 400 / 1210; without pattern it returns 200.
Workaround that restores interactive use: "permissions": {"deny": ["Artifact"]} in settings.json removes the tool from the request (verified: 33 -> 32 tools, 200).
Claude Model
Not sure / Multiple models
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.263 (Claude Code)
Claude Code Version
2.1.266 (Claude Code); also reproduced on 2.1.265
Platform
Other
Operating System
macOS
Terminal/Shell
Other
Additional Information
Platform detail: Anthropic-compatible third-party backend (Z.AI GLM glm-5.3) behind a local Anthropic-compatible proxy (9router); the standalone curl above hits the backend directly. Terminal: WezTerm. macOS 26 on Apple Silicon.
Version bracket, same playbook, same prompt, interactive:
- 2.1.238, 2.1.252, 2.1.261, 2.1.263: Artifact tool sent, no
\p{..}pattern in it, HTTP 200 - 2.1.265, 2.1.266: Artifact tool sent with the
fieldpattern, HTTP 400 / 1210
Bisection of the failing body (one thing changed at a time): swapping in print-mode tools fixes it; adding only Artifact to the print-mode tool list breaks it (AskUserQuestion, EnterPlanMode, ExitPlanMode, SendFeedback individually do not); stripping propertyNames, prefixItems, additionalProperties, anyOf, const or maxLength from the Artifact schema does not help; stripping pattern does; of the six distinct patterns only the field one fails.
Related: #84056 (interactive-only 400 from input_schema keywords on a third-party backend).
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Also affected — confirming this is present on 2.1.266 as well (regression first shipped in 2.1.265; 2.1.263 is the last working build here). Same report also left on #92969, which is currently labeled duplicate of this issue.
Environment
ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic), modeldeepseek-v4-flash[1m]Symptoms
400 Invalid schema for function 'Artifact': "…" is not a "regex"— even a plain "hi". Every new session, in any directory; no workaround flag.^(?!__.*__$)[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}"\\./[\]]{1,200}$claude -p) works — consistent with the Artifact tool not being sent there.Minimal repro (single
/v1/messagesrequest with one tool whosepatternis set):200 OK400 … is not a "regex"\p{...}-only variants each pass alone → it's the combined negated class that strict validators rejectDeepSeek advertises
/anthropicas Claude Code-compatible, so this breaks every DeepSeek + Claude Code user on 2.1.265/2.1.266. A fix on either side resolves it: drop\p{...}/ use explicit code-point ranges, or withholdpatternon non-first-party endpoints. Happy to share logs or the full repro payload.Temporary workaround for native Windows installation (non-npm): roll back to
v2.1.263claude-win32-x64.zipfrom v2.1.263, and extract it to getclaude.exe.claude.exedirectory in your system:C:\Users\Username\.local\bin, and back up the currentclaude.exeasclaude.exe.old.2.1.266claude.exeto the current directory.claudeagain; the version will now have reverted to2.1.263.Independent confirmation + a few data points that may help others via search:
Environment: 2.1.266, native install, WSL2,
ANTHROPIC_BASE_URL→ a new-api relay whose glm-5.3 channel forwards to the GLM native API.Two error surfaces, one trigger — depending on which upstream the relay routes to, the same request fails as either:
API Error: 400 [1210][API 调用参数有误,请检查文档。](glm-5.3 native path), orAPI Error: 400 Invalid schema for function 'Artifact': "^(?!__.*__$)[^\p{Cc}\p{Cf}\p{Zl}\p{Zp}\"\\\\./[\\]]{1,200}$" is not a "regex"(relay's OpenAI-compat conversion path)A minimal A/B against the same endpoint confirms the pattern is the sole trigger: an identical tool definition without the
patternkeyword → 200 OK; with it → 400.Workaround confirmed end-to-end — in
~/.claude/settings.json(user-level settings; a project-level.claude/settings.jsonworks too), merge adenylist into the existingpermissionsblock:The denied tool is dropped from the request entirely, so the validator never sees the pattern. Takes effect on the next session you start — already-running sessions keep the tool in their context. Denying just
"Artifact"as in the OP also suffices; I denied the whole family defensively. Verified with a fresh interactive TUI session through the same relay: zero errors, normal responses.Session-type discriminator for triage: SDK-spawned sessions (
entrypoint=sdk-cli, e.g. bridges driving Claude Code through the SDK) andclaude -pnever ship the tool and keep working — handy for telling this regression apart from a relay-side outage.Pinning caveat for the 2.1.263 downgrade path:
"autoUpdates": falsein.claude.jsondid not stop the native installer — both 2.1.265 and 2.1.266 auto-installed overnight. Staying on 2.1.263 requiresDISABLE_AUTOUPDATER=1(env), not just the setting.