gofiber/fiber · error

sse: handler panic: %v

Error message

sse: handler panic: %v

What it means

Fiber wraps your SSE handler in a recover; if the handler panics, the recovered value is wrapped as 'sse: handler panic: %v', the stream is closed, and OnClose (if set) receives this error. This keeps one client's panic from crashing the whole server process.

Source

Thrown at middleware/sse/sse.go:55

		lastEventID := c.Get(fiber.HeaderLastEventID)

		c.Abandon()

		return c.SendStreamWriter(func(w *bufio.Writer) {
			stream := newStream(streamContext, w, lastEventID, c.App().Config().JSONEncoder)
			var streamErr error
			defer func() {
				if cfg.OnClose != nil {
					finalErr := streamErr
					if finalErr == nil {
						finalErr = stream.Err()
					}
					cfg.OnClose(c, finalErr)
				}
			}()
			defer func() {
				if recovered := recover(); recovered != nil {
					streamErr = fmt.Errorf("sse: handler panic: %v", recovered)
				}
			}()
			defer stream.closeStream()

			if cfg.Retry > 0 {
				streamErr = stream.Retry(cfg.Retry)
				if streamErr != nil {
					return
				}
			}

			if !cfg.DisableHeartbeat {
				stopHeartbeat := stream.startHeartbeat(cfg.HeartbeatInterval)
				if stopHeartbeat != nil {
					defer stopHeartbeat()
				}
			}

View on GitHub (pinned to 9a4c7e57fe)

Solutions

  1. Inspect the wrapped panic message to locate the panic site and fix the root cause.
  2. Add comma-ok type assertions and nil checks for values from ctx/external calls.
  3. Protect shared maps/state with a mutex; avoid concurrent map writes.

Example fix

// before
Handler: func(c fiber.Ctx, s *sse.Stream) error {
    name := c.Locals("user").(*User).Name // (*User)(nil).Name -> panic
    ...
}

// after
Handler: func(c fiber.Ctx, s *sse.Stream) error {
    u, ok := c.Locals("user").(*User)
    if !ok || u == nil {
        return c.SendStatus(fiber.StatusUnauthorized)
    }
    name := u.Name
    ...
}
Defensive patterns

Strategy: try-catch

Try / catch

// Wrap risky handler logic in your own recover for structured logging.
func safe(fn fiber.Handler) fiber.Handler {
    return func(c fiber.Ctx) (err error) {
        defer func() {
            if r := recover(); r != nil {
                log.Errorf("handler panic: %v\n%s", r, debug.Stack())
                err = fiber.ErrInternalServerError
            }
        }()
        return fn(c)
    }
}

Prevention

When it happens

Trigger: Any panic inside the function passed to sse.New(Config{Handler: ...}) while serving a client: nil-pointer dereference, index-out-of-range, concurrent map write, failed type assertion without ok.

Common situations: Unhandled nil from a DB driver or map lookup; concurrent map writes; type assertions on interface values from the stream/ctx; third-party lib panics.

Related errors


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/9ddf10af479275bb.json. Report an issue: GitHub.