Type soundness is a primary selling point (#1278). Right now the dependency graph quietly holds three different Zod module instances, and packages that require Zod 4 are being handed Zod 3.
Measured on origin/main
deno info npm:@modelcontextprotocol/sdk
peer zod@^4.0.0: resolved to 3.25.76 ← violated constraint, not a preference
npm:/zod@3.25.76
deno info npm:@anthropic-ai/sdk → peer zod@^4.0.0: resolved to 3.25.76
deno info npm:openai → peer zod@^4.0.0: resolved to 3.25.76 (×2 paths)
The three instances in one lock:
| Instance |
Who binds to it |
jsr:@zod/zod@4.4.3 |
18 workspace deno.json files — all of our own code |
npm:zod@4.4.3 |
better-call@1.3.6 (better-auth path) |
npm:zod@3.25.76 |
@anthropic-ai/sdk, @modelcontextprotocol/sdk, openai, @tanstack/ai-mcp, zod-to-json-schema |
Most of the cluster does not pin v3 — but two paths do (corrected 2026-08-05)
Every package in that v3 cluster already accepts Zod 4:
| Package |
peerDependencies.zod |
@anthropic-ai/sdk |
^3.25.0 || ^4.0.0 |
@modelcontextprotocol/sdk |
^3.25 || ^4.0 |
openai |
^3.25 || ^4.0 |
zod-to-json-schema (3.25.2, latest) |
^3.25.28 || ^4 |
So there is no upstream blocker to remove — this is ours to fix. The npm subgraph has no npm-side Zod 4 to dedupe onto because our own code supplies Zod from JSR, so Deno resolves those peers independently and lands on 3.25.76.
Why it is a correctness problem, not tidiness
A schema built with jsr:@zod/zod is a different module instance from npm:zod@4.4.3 and from npm:zod@3.25.76. Across that boundary instanceof fails, brand/nominal checks fail, and structurally-identical types stop being assignable — the class of failure that produced #1250 (Zod-3 plugin against Zod-4 scaffolds, every numeric query param 400ing) and #1249. It also means an AI-plugin path can hand a v4 schema to an SDK holding v3.
Also: the catalog is npm-only (AGENTS.md), so while Zod comes from JSR it cannot live in the catalog — there is no single source of version truth for the repo's most cross-cutting dependency.
Acceptance (rescoped 2026-08-05 — see the correction comment)
The original "exactly one Zod instance" bar is not reachable in 0.0.5: @ag-ui/core@0.0.52
hard-depends on zod: ^3.22.4 with no || ^4, and jsr:@olli/kvdex@3.6.7 (latest) also
materialises Zod 3. Collapsing to one instance needs either a TanStack AI 0.39→0.43 cluster
upgrade — which currently drags in a canary AG-UI build — or replacing/forking/removing
kvdex. Neither belongs in a release we are about to cut.
Scoped to what is real and verifiable now:
Collapsing to a single instance moves to 0.0.6, gated on AG-UI accepting Zod 4 or a kvdex
decision. Filed separately so it is tracked rather than forgotten.
Type soundness is a primary selling point (#1278). Right now the dependency graph quietly holds three different Zod module instances, and packages that require Zod 4 are being handed Zod 3.
Measured on
origin/mainThe three instances in one lock:
jsr:@zod/zod@4.4.3deno.jsonfiles — all of our own codenpm:zod@4.4.3better-call@1.3.6(better-auth path)npm:zod@3.25.76@anthropic-ai/sdk,@modelcontextprotocol/sdk,openai,@tanstack/ai-mcp,zod-to-json-schemaMost of the cluster does not pin v3 — but two paths do (corrected 2026-08-05)
Every package in that v3 cluster already accepts Zod 4:
peerDependencies.zod@anthropic-ai/sdk^3.25.0 || ^4.0.0@modelcontextprotocol/sdk^3.25 || ^4.0openai^3.25 || ^4.0zod-to-json-schema(3.25.2, latest)^3.25.28 || ^4So there is no upstream blocker to remove — this is ours to fix. The npm subgraph has no npm-side Zod 4 to dedupe onto because our own code supplies Zod from JSR, so Deno resolves those peers independently and lands on 3.25.76.
Why it is a correctness problem, not tidiness
A schema built with
jsr:@zod/zodis a different module instance fromnpm:zod@4.4.3and fromnpm:zod@3.25.76. Across that boundaryinstanceoffails, brand/nominal checks fail, and structurally-identical types stop being assignable — the class of failure that produced #1250 (Zod-3 plugin against Zod-4 scaffolds, every numeric query param 400ing) and #1249. It also means an AI-plugin path can hand a v4 schema to an SDK holding v3.Also: the catalog is npm-only (AGENTS.md), so while Zod comes from JSR it cannot live in the catalog — there is no single source of version truth for the repo's most cross-cutting dependency.
Acceptance (rescoped 2026-08-05 — see the correction comment)
The original "exactly one Zod instance" bar is not reachable in 0.0.5:
@ag-ui/core@0.0.52hard-depends on
zod: ^3.22.4with no|| ^4, andjsr:@olli/kvdex@3.6.7(latest) alsomaterialises Zod 3. Collapsing to one instance needs either a TanStack AI 0.39→0.43 cluster
upgrade — which currently drags in a canary AG-UI build — or replacing/forking/removing
kvdex. Neither belongs in a release we are about to cut.
Scoped to what is real and verifiable now:
@anthropic-ai/sdk,@modelcontextprotocol/sdk,openai,zod-to-json-schema) resolves onto npm Zod 4 — nopeer zod@^4.0.0: resolved to 3.xline survives for any of them in
deno infodeno.jsonfiles@orpc/zodusage is on the v4 surface throughout (consistent with the service: ZodSmartCoercionPlugin imported from @orpc/zod (Zod 3) while scaffolds use Zod 4 — coercion silently no-ops, every numeric query param 400s #1250 fix)(
@ag-ui/corehard^3.22.4,jsr:@olli/kvdex@3.6.7) rather than left implicitpublish:dry-runanddeno doc --lintstay clean across the 18-package changeCollapsing to a single instance moves to 0.0.6, gated on AG-UI accepting Zod 4 or a kvdex
decision. Filed separately so it is tracked rather than forgotten.