Files
gruperly/.agents/skills/zod/references/object-strict-vs-strip.md
2026-09-04 16:49:24 -03:00

110 lines
2.9 KiB
Markdown

---
title: Choose strict() vs strip() for Unknown Keys
impact: MEDIUM-HIGH
impactDescription: Default passthrough mode leaks unexpected data; strict() catches schema mismatches, strip() silently removes extras
tags: object, strict, strip, passthrough
---
## Choose strict() vs strip() for Unknown Keys
By default, Zod objects use `.strip()` behavior, silently removing unrecognized keys. This can hide schema/data mismatches. Use `.strict()` to reject unknown keys (catching errors) or explicitly use `.strip()` to document the intention.
**Default behavior (strip - silent removal):**
```typescript
import { z } from 'zod'
const userSchema = z.object({
id: z.string(),
name: z.string(),
})
const input = {
id: '123',
name: 'John',
role: 'admin', // Extra field
secretToken: 'abc123', // Another extra field
}
const user = userSchema.parse(input)
// { id: '123', name: 'John' }
// Extra fields silently removed - was this intentional?
```
**Using strict() to catch schema mismatches:**
```typescript
import { z } from 'zod'
const userSchema = z.object({
id: z.string(),
name: z.string(),
}).strict()
const input = {
id: '123',
name: 'John',
role: 'admin',
}
userSchema.parse(input)
// ZodError: Unrecognized key(s) in object: 'role'
// This catches:
// - Client sending fields the server doesn't expect
// - Schema out of sync with actual data structure
// - Typos in field names
```
**When to use each mode:**
```typescript
// strict() - Catch unexpected data (API contracts)
const apiRequestSchema = z.object({
action: z.string(),
payload: z.unknown(),
}).strict() // Fail if client sends unknown fields
// strip() - Clean up data (explicit intention)
const dbInsertSchema = z.object({
name: z.string(),
email: z.string(),
}).strip() // Explicitly remove metadata before insert
// passthrough() - Keep everything (pass-through proxy)
const proxySchema = z.object({
id: z.string(),
}).passthrough() // Keep fields we don't validate
const input = { id: '123', extra: 'data' }
proxySchema.parse(input) // { id: '123', extra: 'data' }
```
**Choosing the right mode:**
| Mode | Behavior | Use When |
|------|----------|----------|
| `.strict()` | Reject unknown keys | API contracts, security-sensitive, debugging |
| `.strip()` (default) | Remove unknown keys | General validation, data cleaning |
| `.passthrough()` | Keep unknown keys | Proxying, partial validation |
**Handling specific unknown keys:**
```typescript
const schema = z.object({
id: z.string(),
name: z.string(),
}).catchall(z.unknown()) // Allow any additional fields of any type
// Or restrict additional fields to specific type
const metadataSchema = z.object({
id: z.string(),
}).catchall(z.string()) // Only allow string extras
```
**When NOT to use this pattern:**
- `.strict()`: When forwarding data to another system that may add fields
- `.passthrough()`: When you need to ensure only known fields are stored
Reference: [Zod API - Objects](https://zod.dev/api#objects)