Files
gruperly/.agents/skills/zod/references/parse-use-safeparse.md
2026-09-04 16:49:24 -03:00

2.7 KiB

title, impact, impactDescription, tags
title impact impactDescription tags
Use safeParse() for User Input CRITICAL parse() throws exceptions on invalid data; unhandled exceptions crash servers and expose stack traces to users parse, safeParse, error-handling, validation

Use safeParse() for User Input

parse() throws a ZodError when validation fails, which crashes your application if not caught. safeParse() returns a result object that you can inspect without try/catch. Use safeParse() for any user-provided or external data.

Incorrect (parse without error handling):

import { z } from 'zod'
import { NextRequest, NextResponse } from 'next/server'

const createUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1),
})

export async function POST(req: NextRequest) {
  const body = await req.json()

  // If validation fails, this throws and crashes the handler
  const user = createUserSchema.parse(body)

  // Never reached if parse throws
  await db.users.create({ data: user })
  return NextResponse.json({ success: true })
}
// Result: 500 Internal Server Error with stack trace

Correct (using safeParse):

import { z } from 'zod'
import { NextRequest, NextResponse } from 'next/server'

const createUserSchema = z.object({
  email: z.string().email(),
  name: z.string().min(1),
})

export async function POST(req: NextRequest) {
  const body = await req.json()

  const result = createUserSchema.safeParse(body)

  if (!result.success) {
    // Return structured error response
    return NextResponse.json(
      { error: 'Validation failed', issues: result.error.issues },
      { status: 400 }
    )
  }

  // result.data is typed correctly
  await db.users.create({ data: result.data })
  return NextResponse.json({ success: true })
}

The result object structure:

// Success case
{ success: true, data: T }

// Error case
{ success: false, error: ZodError }

// Type narrowing works automatically
if (result.success) {
  result.data  // T - fully typed
} else {
  result.error  // ZodError
  result.error.issues  // Array of validation issues
}

When parse() is acceptable:

// Internal data you control - parse is fine
const config = configSchema.parse(JSON.parse(process.env.CONFIG))

// Test assertions - parse throws helpful errors
expect(() => schema.parse(invalidData)).toThrow()

// Schema development - see errors immediately
schema.parse(testData)  // See what fails during development

When NOT to use this pattern:

  • Internal configuration parsing where invalid data should crash early
  • Tests where you want exceptions to fail the test
  • Scripts where you want to see the full error

Reference: Zod API - safeParse