# Postmortem: Error Thrown When Logging ZodError in TypeScript
## Summary
An attempt to log Zod validation errors using `console.log(error)` unexpectedly throws an error instead of printing diagnostic information. This occurs because `ZodError` contains circular references via its `.issues` array, causing JSON serialization to fail during console output.
## Root Cause
- **Circular references in ZodError**: The `ZodError` object links issues backwards to their parent error via a `.root` property, creating a circular structure that `console.log` cannot serialize.
- **Default JSON conversion**: Node.js's `console.log` implicitly tries to serialize objects using JSON-like methods, which fails on circular references.
## Why This Happens in Real Systems
- Zod errors often propagate through layers (UI, API, services) where developers log objects for debugging.
- Circumstances triggering Zod validation errors (e.g., invalid user input) are exactly when developers need informative logging.
- Production systems log errors centrally (Sentry, ELK) where serialization failures cause lost context.
## Real-World Impact
- **Debugging blindspots**: Critical validation error details disappear from logs.
- **Cascading failures**: An unhandled "Converting circular structure" exception might crash worker processes.
- **Delayed incident resolution**: Missing error context prolongs outage investigations.
## Example or Code
### ❌ Problematic Pattern
```typescript
import { z } from 'zod';
const schema = z.string();
const result = schema.safeParse(3);
// Throws "TypeError: Converting circular structure to JSON"
console.log(result.error);
✅ Correct Approach
// Log formatted errors instead of raw object
console.log(result.error.toString());
// Or serialize explicitly:
console.log(JSON.stringify(result.error, null, 2));
// Alternative: Use Zod's built-in formatting
console.log(result.error.format());
How Senior Engineers Fix It
- Avoid raw logging: Never log
ZodError instances directly. Always serialize explicitly:
console.error(JSON.stringify(error, null, 2));
- Use Zod’s formatters: Leverage
error.format() for structured data or error.toString() for human-readable output.
- Centralized exception handling: Wrap logging logic to automatically serialize errors before transmission:
function safeLogError(error: unknown) {
if (error instanceof z.ZodError) {
console.error(JSON.stringify(error, null, 2));
} else {
console.error(error);
}
}
- Type narrowing: Add explicit runtime checks for
ZodError instances before handling.
Why Juniors Miss It
- Assumption of safe serialization: Expecting
console.log to handle complex objects like native types.
- Untested error paths: Validation errors often occur outside happy-path testing scenarios.
- TypeScript blind spots: Trusting type safety without considering runtime peculiarities of specific classes.
- Documentation gaps: Zod’s API docs emphasize validation, not serialization pitfalls.