> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Recover

> Panic recovery middleware for graceful error handling.

## Overview

The `recover` middleware catches panics in handlers and converts them to proper error responses. It prevents your server from crashing and logs stack traces for debugging.

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/recover"
```

## Quick Start

```go theme={null}
app := mizu.New()

// Add as first middleware
app.Use(recover.New())
```

## Configuration

| Option              | Type                                 | Default      | Description                |
| ------------------- | ------------------------------------ | ------------ | -------------------------- |
| `StackSize`         | `int`                                | `4096`       | Stack trace buffer size    |
| `DisableStackAll`   | `bool`                               | `false`      | Limit to current goroutine |
| `DisablePrintStack` | `bool`                               | `false`      | Disable stack logging      |
| `ErrorHandler`      | `func(*mizu.Ctx, any, []byte) error` | -            | Custom panic handler       |
| `Logger`            | `*slog.Logger`                       | `c.Logger()` | Custom logger              |

## Examples

### Basic Recovery

```go theme={null}
app.Use(recover.New())

app.Get("/", func(c *mizu.Ctx) error {
    panic("something went wrong") // Caught by recover
})
// Returns 500 Internal Server Error
```

### Custom Error Handler

```go theme={null}
app.Use(recover.WithOptions(recover.Options{
    ErrorHandler: func(c *mizu.Ctx, err any, stack []byte) error {
        // Log to error tracking service
        errorTracker.Report(err, string(stack))

        return c.JSON(500, map[string]string{
            "error": "Internal server error",
        })
    },
}))
```

### Disable Stack Trace

```go theme={null}
// Production: don't log stack traces
app.Use(recover.WithOptions(recover.Options{
    DisablePrintStack: true,
}))
```

### Custom Logger

```go theme={null}
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

app.Use(recover.WithOptions(recover.Options{
    Logger: logger,
}))
```

### With Request ID

```go theme={null}
app.Use(requestid.New())
app.Use(recover.WithOptions(recover.Options{
    ErrorHandler: func(c *mizu.Ctx, err any, stack []byte) error {
        c.Logger().Error("panic recovered",
            "error", err,
            "request_id", requestid.Get(c),
            "stack", string(stack),
        )
        return c.Text(500, "Internal Server Error")
    },
}))
```

## API Reference

```go theme={null}
func New() mizu.Middleware
func WithOptions(opts Options) mizu.Middleware
```

## Log Output

```json theme={null}
{
    "level": "ERROR",
    "msg": "panic recovered",
    "error": "runtime error: index out of range",
    "stack": "goroutine 1 [running]:\nmain.handler..."
}
```

## Technical Details

The recover middleware uses Go's built-in `defer` and `recover()` mechanisms to catch panics in handlers. Here's how it works internally:

### Implementation Architecture

1. **Panic Recovery**: A deferred function wraps the next handler, catching any panic that occurs during request processing
2. **Stack Trace Capture**: Uses `runtime/debug.Stack()` to capture the full stack trace when a panic occurs
3. **Stack Size Management**: Truncates stack traces to the configured `StackSize` (default 4096 bytes) to prevent memory issues
4. **Logging Integration**: Integrates with Go's `log/slog` package for structured logging of panic information
5. **Error Propagation**: Converts recovered panics into proper HTTP error responses

### Key Implementation Details

* The middleware returns a closure that wraps the next handler with a deferred recovery function
* When `DisablePrintStack` is false, `debug.Stack()` captures the current goroutine's stack trace
* The stack trace is truncated if it exceeds `StackSize` to prevent excessive memory usage
* If a custom `ErrorHandler` is provided, it receives the panic value and stack trace for custom handling
* Default behavior returns a 500 Internal Server Error with the standard HTTP status text
* The logger defaults to `c.Logger()` if no custom logger is specified

### Performance Considerations

* Minimal overhead when no panic occurs (just a defer statement)
* Stack trace capture only happens during panics
* Configurable stack size prevents unbounded memory allocation
* Option to disable stack printing for production environments

## Best Practices

* Always add as the first middleware
* Log panics for debugging
* Don't expose stack traces to users in production
* Use with request ID for correlation

## Testing

The recover middleware includes comprehensive test coverage for all features and edge cases:

| Test Case                                | Description                                   | Expected Behavior                                                                         |
| ---------------------------------------- | --------------------------------------------- | ----------------------------------------------------------------------------------------- |
| `TestNew/recovers from panic`            | Handler that panics with "test panic"         | Returns 500 Internal Server Error status                                                  |
| `TestNew/passes through normal requests` | Handler that returns normally without panic   | Returns 200 OK with response body "ok"                                                    |
| `TestWithOptions_ErrorHandler`           | Custom error handler captures panic and stack | Returns 503 Service Unavailable with "custom error", captures panic value and stack trace |
| `TestWithOptions_DisablePrintStack`      | DisablePrintStack option enabled              | Returns 500 status, no stack trace in log output                                          |
| `TestWithOptions_CustomLogger`           | Custom slog.Logger provided                   | Panic is logged with "panic recovered" message and panic details                          |
| `TestWithOptions_StackSize`              | StackSize set to 100 bytes                    | Captured stack trace is truncated to maximum 100 bytes                                    |

## Related Middlewares

* [requestid](/middlewares/requestid) - Request tracing
* [timeout](/middlewares/timeout) - Request timeout
