go 22 lines · 1 tab

Panic recovery middleware for HTTP servers

Leah Thompson Jan 2026
1 tab
package middleware

import (
  "net/http"

  "go.uber.org/zap"
)

func Recover(log *zap.Logger) func(http.Handler) http.Handler {
  return func(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
      defer func() {
        if v := recover(); v != nil {
          log.Error("panic.recovered", zap.Any("panic", v), zap.String("path", r.URL.Path))
          http.Error(w, "internal server error", http.StatusInternalServerError)
        }
      }()

      next.ServeHTTP(w, r)
    })
  }
}
1 file · go Explain with highlit

Even in Go, panics happen: a nil pointer in an edge case, a bad slice index, or a library bug. I don't want a single request to take down the whole process, so I wrap handlers with a recovery middleware that captures panics, logs them with request context, and returns a safe 500. The important detail is to keep the response body generic (don't leak internals) while still capturing enough debug information in logs. I also attach a request_id header so a customer report can be tied to a specific failure. This middleware is not a replacement for tests, but it turns catastrophic crashes into contained errors and buys you time to ship a fix without burning a whole deploy.


Related snips

Share this code

Here's the card — post it anywhere.

Panic recovery middleware for HTTP servers — share card
Link copied