Added AI skills
This commit is contained in:
118
.agents/skills/zod/references/error-custom-messages.md
Normal file
118
.agents/skills/zod/references/error-custom-messages.md
Normal file
@@ -0,0 +1,118 @@
|
||||
---
|
||||
title: Provide Custom Error Messages
|
||||
impact: HIGH
|
||||
impactDescription: Default messages like "Expected string, received number" confuse users; custom messages like "Email is required" are actionable
|
||||
tags: error, messages, user-experience, validation
|
||||
---
|
||||
|
||||
## Provide Custom Error Messages
|
||||
|
||||
Zod's default error messages are technical and confusing for end users. Provide custom messages that are clear, specific, and actionable. This dramatically improves user experience when validation fails.
|
||||
|
||||
**Incorrect (default error messages):**
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
|
||||
const signupSchema = z.object({
|
||||
email: z.string().email(),
|
||||
password: z.string().min(8),
|
||||
age: z.number().min(18),
|
||||
})
|
||||
|
||||
signupSchema.parse({ email: 'bad', password: '123', age: 15 })
|
||||
// ZodError issues:
|
||||
// - "Invalid email"
|
||||
// - "String must contain at least 8 character(s)"
|
||||
// - "Number must be greater than or equal to 18"
|
||||
// Users see: "String must contain at least 8 character(s)" - what string?
|
||||
```
|
||||
|
||||
**Correct (custom error messages):**
|
||||
|
||||
```typescript
|
||||
import { z } from 'zod'
|
||||
|
||||
const signupSchema = z.object({
|
||||
email: z.string({
|
||||
required_error: 'Email is required',
|
||||
invalid_type_error: 'Email must be text',
|
||||
}).email('Please enter a valid email address'),
|
||||
|
||||
password: z.string({
|
||||
required_error: 'Password is required',
|
||||
}).min(8, 'Password must be at least 8 characters'),
|
||||
|
||||
age: z.number({
|
||||
required_error: 'Age is required',
|
||||
invalid_type_error: 'Age must be a number',
|
||||
}).min(18, 'You must be at least 18 years old'),
|
||||
})
|
||||
|
||||
signupSchema.parse({ email: 'bad', password: '123', age: 15 })
|
||||
// ZodError issues:
|
||||
// - "Please enter a valid email address"
|
||||
// - "Password must be at least 8 characters"
|
||||
// - "You must be at least 18 years old"
|
||||
```
|
||||
|
||||
**Message types and when they trigger:**
|
||||
|
||||
```typescript
|
||||
const schema = z.string({
|
||||
// When field is undefined
|
||||
required_error: 'This field is required',
|
||||
|
||||
// When field is wrong type (e.g., number instead of string)
|
||||
invalid_type_error: 'This field must be text',
|
||||
|
||||
// Fallback for any other error
|
||||
message: 'Invalid value',
|
||||
})
|
||||
.min(1, 'Cannot be empty') // When length < 1
|
||||
.max(100, 'Too long') // When length > 100
|
||||
.email('Invalid email format') // When format fails
|
||||
```
|
||||
|
||||
**Using error maps for consistent messaging:**
|
||||
|
||||
```typescript
|
||||
const customErrorMap: z.ZodErrorMap = (issue, ctx) => {
|
||||
// Customize messages by error code
|
||||
if (issue.code === z.ZodIssueCode.too_small) {
|
||||
if (issue.type === 'string') {
|
||||
return { message: `Must be at least ${issue.minimum} characters` }
|
||||
}
|
||||
if (issue.type === 'number') {
|
||||
return { message: `Must be at least ${issue.minimum}` }
|
||||
}
|
||||
}
|
||||
|
||||
if (issue.code === z.ZodIssueCode.invalid_type) {
|
||||
if (issue.expected === 'string') {
|
||||
return { message: 'Must be text' }
|
||||
}
|
||||
}
|
||||
|
||||
// Default to Zod's message
|
||||
return { message: ctx.defaultError }
|
||||
}
|
||||
|
||||
// Apply globally
|
||||
z.setErrorMap(customErrorMap)
|
||||
|
||||
// Or per-schema
|
||||
schema.parse(data, { errorMap: customErrorMap })
|
||||
```
|
||||
|
||||
**Good error message principles:**
|
||||
- Say what's wrong: "Password too short" not "Invalid password"
|
||||
- Say how to fix it: "at least 8 characters" not just "too short"
|
||||
- Use user's language: "email" not "string field at path .email"
|
||||
- Be specific: "Must be a positive number" not "Invalid"
|
||||
|
||||
**When NOT to use this pattern:**
|
||||
- Internal development scripts where technical errors are fine
|
||||
- When you'll map errors to user-facing messages in the UI layer
|
||||
|
||||
Reference: [Zod Error Customization](https://zod.dev/error-customization)
|
||||
Reference in New Issue
Block a user