# How to Use Zod's Catch Method for Default Values on Parse Failures

> Learn how to use Zod's catch method to provide default values on parse failures, preventing errors and ensuring valid data in your application. Simplify data handling with Zod.

- Repository: [Colin McDonnell/zod](https://github.com/colinhacks/zod)
- Tags: how-to-guide
- Published: 2026-02-23

---

**Zod's `catch` method creates a `$ZodCatch` wrapper schema that returns a static or computed fallback value whenever inner validation fails, ensuring your application receives valid data instead of throwing errors.**

Zod's `catch` method provides a defensive mechanism for handling validation failures by supplying default values at the schema level. As implemented in the `colinhacks/zod` repository, this feature intercepts parsing errors in [`packages/zod/src/v4/core/schemas.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/core/schemas.ts) and substitutes your specified fallback before the error propagates. This approach eliminates the need for `try/catch` blocks around every `parse` call while maintaining type safety.

## How Zod's Catch Method Works Internally

The `catch` method generates a **wrapper schema** that executes a six-step resolution process during parsing. According to the source code in [`packages/zod/src/v4/core/schemas.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/core/schemas.ts), the runtime behavior follows this exact sequence:

1. **Schema Instantiation**: Calling `z.catch(inner, catchValue)` in [`packages/zod/src/v4/core/api.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/core/api.ts) (lines 1495-1507) creates a `$ZodCatch` instance that stores the inner schema and your fallback value or function.

2. **Inner Validation Execution**: The wrapper first runs `innerType._zod.run` to validate the input against the original schema requirements (lines 3764-3769).

3. **Failure Detection**: If the inner result contains issues (verified via `result.issues.length` at lines 3784-3790), Zod identifies the validation as failed.

4. **Fallback Computation**: The stored `catchValue` receives a **context object** containing `ctx.error.issues`, the original payload, and raw input, then returns the replacement value (lines 3786-3792).

5. **Issue Suppression**: After successful fallback execution, Zod empties the issues array (`payload.issues = []`) to ensure the outer parse call succeeds (lines 3793-3795).

6. **Result Return**: The modified payload containing your default value returns to the caller, effectively masking the original validation failure.

The tree-shakable mini build in [`packages/zod/src/v4/mini/schemas.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/mini/schemas.ts) (lines 1541-1552) implements this identical logic for bundle-conscious applications.

## Implementing Default Values with Zod Catch

### Static Fallback Values

Provide a constant default that applies regardless of why validation failed. This pattern works best for configuration objects or primitive types with clear safe defaults.

```typescript
import { z } from "zod";

const schema = z.catch(z.string(), "fallback");

console.log(z.parse(schema, "hello")); // → "hello"
console.log(z.parse(schema, 123));     // → "fallback"

```

### Dynamic Defaults Based on Validation Errors

Access the error context to compute conditional defaults using the `ctx` parameter, which exposes the specific validation issues that occurred.

```typescript
import { z } from "zod";

const schema = z.catch(z.string(), (ctx) => {
  // ctx.error.issues contains the array of validation failures
  return `${ctx.error.issues.length} validation error(s) detected`;
});

console.log(z.parse(schema, 42)); // → "1 validation error(s) detected"

```

### SafeParse Integration

Even when using `z.safeParse`, the `catch` wrapper guarantees `success: true` by resolving failures before the result object is constructed.

```typescript
import { z } from "zod";

const schema = z.catch(z.object({ age: z.number() }), { age: 0 });

const result = z.safeParse(schema, { name: "Alice" });
console.log(result.success); // true
console.log(result.data);    // { age: 0 }

```

### Tree-Shakable Mini Build

The lightweight `zod/mini` export supports identical `catch` functionality for applications requiring minimal bundle size.

```typescript
import { z } from "zod/mini";

const schema = z.catch(z.number(), () => 99);
console.log(z.parse(schema, "not a number")); // → 99

```

## Key Source Files in the Zod Repository

Understanding the implementation requires familiarity with these specific files:

- **[`packages/zod/src/v4/core/api.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/core/api.ts)**: Defines the public `_catch` factory function that constructs `$ZodCatch` schema instances.
- **[`packages/zod/src/v4/core/schemas.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/core/schemas.ts)**: Contains the runtime `run` method that executes the six-step fallback logic, including the `catchValue` invocation and issue clearing.
- **[`packages/zod/src/v4/mini/schemas.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/mini/schemas.ts)**: Provides the mini-build equivalent implementation optimized for tree-shaking.
- **[`packages/zod/src/v4/mini/tests/index.test.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/mini/tests/index.test.ts)**: Houses the test suite demonstrating both static and dynamic catch value behaviors.

## Summary

- **Zod's `catch` method** creates a `$ZodCatch` wrapper that intercepts validation failures in [`packages/zod/src/v4/core/schemas.ts`](https://github.com/colinhacks/zod/blob/main/packages/zod/src/v4/core/schemas.ts) before they throw.
- **Static fallbacks** provide constant default values, while **dynamic fallbacks** receive a context object with `ctx.error.issues` for conditional logic based on specific failure types.
- The implementation clears the internal issues array after fallback execution (`payload.issues = []`), ensuring `parse` returns successfully rather than propagating errors.
- Both the standard and **mini builds** (`zod/mini`) support identical `catch` functionality with the same six-step resolution process.

## Frequently Asked Questions

### What is the difference between Zod's `catch` and `default` methods?

**`z.default()`** provides a fallback only when the input is explicitly `undefined`, whereas **`z.catch()`** activates when any validation error occurs—including type mismatches, constraint violations, or malformed data. Use `catch` when you need to handle invalid inputs gracefully, and `default` when you only need to handle missing values.

### Can I access the original input value in the catch function?

Yes, the catch function receives a **context object** that includes the original payload, raw input, and a complete error object with the issues array. This allows you to inspect the failed value or error details when computing your fallback, as shown in the dynamic defaults example.

### Does Zod catch work with asynchronous schemas?

The `catch` method supports both synchronous and asynchronous parsing workflows. If the inner schema uses `parseAsync`, the `$ZodCatch` wrapper properly handles the Promise rejection and applies your fallback value or function to the resolved error.

### How does catch affect TypeScript type inference?

The `catch` method preserves the inner schema's **output type** while widening the accepted input to `unknown`, ensuring TypeScript recognizes that the schema will always return the expected output type regardless of what input is provided. This maintains strict type safety downstream while allowing flexible input handling.