[BUG] TS2322: Type BetaRunnableTool<{}> is not assignable to type ToolUnion
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?
The Ring 5 documentation introduces betaZodTool as the idiomatic TypeScript way to define tools with Zod schemas. However, the return type of betaZodTool (BetaRunnableTool<T>) is not assignable to ToolUnion, which is the type required by the tools array on messages.stream and messages.create.
This causes a TS2322 type error for developers who follow the docs and then try to use the tool with the standard messages API.
SDK version: 0.91.0
Reproduction
Taken directly from the Ring 5 docs snippet:
import Anthropic from "@anthropic-ai/sdk";
import { betaZodTool } from "@anthropic-ai/sdk/helpers/beta/zod";
import { z } from "zod";
const client = new Anthropic();
const createCalendarEvent = betaZodTool({
name: "create_calendar_event",
description: "Create a calendar event with attendees and optional recurrence.",
inputSchema: z.object({
title: z.string(),
start: z.string().datetime(),
end: z.string().datetime(),
}),
run: async (input) => {
return JSON.stringify({ event_id: "evt_123", status: "created", title: input.title });
},
});
// TS2322: Type 'BetaRunnableTool<{}>' is not assignable to type 'ToolUnion'
client.messages.stream({
model: "claude-opus-4-6",
max_tokens: 1024,
tools: [createCalendarEvent],
messages: [{ role: "user", content: "Schedule a meeting" }],
});
Workaround
Yes, you can cast:
tools: [createCalendarEvent as unknown as Anthropic.Tool]
But this is a hack, not a solution. It silently throws away the type safety that betaZodTool and Zod are supposed to provide in the first place. The whole point of using betaZodTool is to get typed, schema-validated tool definitions — a cast defeats that entirely and leaves you no better off than writing the raw JSON schema by hand.
Notes
The Ring 5 docs do show the correct usage with client.beta.messages.toolRunner(). The problem is there's nothing in the types or docs that warns developers away from using betaZodTool with messages.stream, which is a natural thing to try.
What Should Happen?
Either:
BetaRunnableTool<T>is accepted bymessages.stream/messages.create, or- The docs and/or type signatures make it clear that
betaZodToolis only for use withclient.beta.messages.toolRunner(), not the standard messages API — so developers know they need a different approach formessages.stream
Error Messages/Logs
Steps to Reproduce
- Follow Ring 5 documentation
- Observe type error when registering tool without cast.
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.98
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗