Environment
- @orpc/server: 1.13.14
- TypeScript: 7.0.0-dev (tsgo)
- Node.js: 24.13.0
- OS: macOS (Darwin 25.4.0)
Reproduction
import { oc } from '@orpc/contract'
import { z } from 'zod'
import { os } from '@orpc/server'
const contract = oc.output(z.object({ name: z.string() }))
const procedure = os.contract(contract).handler(async () => {
// No TS error here, even though `age` is not in the output schema
return { name: 'Alice', age: 30 }
})
The handler returns { name: 'Alice', age: 30 } but the contract only defines { name: string }. TypeScript does not flag age as an excess property. At runtime, Zod strips age from the response, so the client never receives it.
Describe the bug
Handler return types are not strictly checked against the contract output schema at compile time. When a handler returns extra properties not defined in the output schema, TypeScript does not report an error. The extra fields are silently stripped at runtime by Zod's .strip() behavior, which can lead to subtle bugs that are hard to catch.
Additional context
This is fundamentally a TypeScript limitation (structural typing allows supersets), but frameworks like oRPC could enforce stricter types using utility types like Exact<T> or StrictOmit patterns to catch this at compile time.
Logs
Environment
Reproduction
The handler returns
{ name: 'Alice', age: 30 }but the contract only defines{ name: string }. TypeScript does not flagageas an excess property. At runtime, Zod stripsagefrom the response, so the client never receives it.Describe the bug
Handler return types are not strictly checked against the contract output schema at compile time. When a handler returns extra properties not defined in the output schema, TypeScript does not report an error. The extra fields are silently stripped at runtime by Zod's
.strip()behavior, which can lead to subtle bugs that are hard to catch.Additional context
This is fundamentally a TypeScript limitation (structural typing allows supersets), but frameworks like oRPC could enforce stricter types using utility types like
Exact<T>orStrictOmitpatterns to catch this at compile time.Logs