claude-code - 💡(How to fix) Fix [BUG] TS2322: Type BetaRunnableTool<{}> is not assignable to type ToolUnion [1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
anthropics/claude-code#52576Fetched 2026-04-24 06:03:27
View on GitHub
Comments
1
Participants
1
Timeline
5
Reactions
0
Participants
Timeline (top)
labeled ×2closed ×1commented ×1unlabeled ×1

Error Message

This causes a TS2322 type error for developers who follow the docs and then try to use the tool with the standard messages API.

Error Messages/Logs

  • Observe type error when registering tool without cast.

Fix Action

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.

Code Example

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" }],
});

---

tools: [createCalendarEvent as unknown as Anthropic.Tool]

---
RAW_BUFFERClick to expand / collapse

Preflight Checklist

  • I have searched existing issues and this hasn't been reported yet
  • This is a single bug report (please file separate reports for different bugs)
  • 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:

  1. BetaRunnableTool<T> is accepted by messages.stream / messages.create, or
  2. The docs and/or type signatures make it clear that betaZodTool is only for use with client.beta.messages.toolRunner(), not the standard messages API — so developers know they need a different approach for messages.stream

Error Messages/Logs

Steps to Reproduce

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

extent analysis

TL;DR

The issue can be resolved by updating the type definitions to make BetaRunnableTool<T> assignable to ToolUnion or by using a different approach for messages.stream that is compatible with betaZodTool.

Guidance

  • Verify that the betaZodTool return type BetaRunnableTool<T> is not assignable to ToolUnion by checking the type definitions.
  • Consider using the client.beta.messages.toolRunner() approach as shown in the Ring 5 docs, which is the intended usage for betaZodTool.
  • If using messages.stream is necessary, explore alternative tool definition methods that are compatible with the standard messages API.
  • Review the documentation to ensure it clearly indicates the usage limitations of betaZodTool to prevent similar issues.

Example

// Intended usage of betaZodTool with client.beta.messages.toolRunner()
client.beta.messages.toolRunner({
  model: "claude-opus-4-6",
  max_tokens: 1024,
  tools: [createCalendarEvent],
  messages: [{ role: "user", content: "Schedule a meeting" }],
});

Notes

The provided workaround using a type cast is not recommended as it defeats the purpose of using betaZodTool for typed, schema-validated tool definitions.

Recommendation

Apply a workaround by using client.beta.messages.toolRunner() instead of messages.stream until the type definitions are updated to support BetaRunnableTool<T> assignability to ToolUnion. This approach ensures that the type safety provided by betaZodTool and Zod is maintained.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

claude-code - 💡(How to fix) Fix [BUG] TS2322: Type BetaRunnableTool<{}> is not assignable to type ToolUnion [1 comments, 1 participants]