gofiber/fiber · error
sse: Handler must not be nil
Error message
sse: Handler must not be nil
What it means
sse.New constructs a Server-Sent Events handler. ConfigDefault leaves Handler nil by design (there is no sensible default stream implementation), so the caller must supply a Config.Handler that writes events to the Stream. New panics when cfg.Handler is nil because there would be nothing to execute on the stream — returning a handler that does nothing would be a silent bug.
Solutions
- Provide a Handler when constructing the config: sse.New(sse.Config{Handler: func(c fiber.Ctx, s *sse.Stream) error { ... }}).
- If you build the Config incrementally, assert cfg.Handler != nil before calling sse.New in tests.
Example fix
// before
app.Get("/events", sse.New()) // panics: no Handler
// after
app.Get("/events", sse.New(sse.Config{
Handler: func(c fiber.Ctx, s *sse.Stream) error {
return s.WriteEvent("ping", "hello")
},
})) Defensive patterns
Strategy: validation
Validate before calling
func newSSE(cfg sse.Config) fiber.Handler {
if cfg.Handler == nil {
log.Fatal("sse: Config.Handler must be set")
}
return sse.New(cfg)
} Type guard
func hasSSEHandler(cfg sse.Config) bool { return cfg.Handler != nil } Prevention
- Wrap sse.New in a helper that asserts Handler is set so the failure is a clear log line, not a raw panic.
- In tests, construct the Config through a builder that requires a Handler argument.
When it happens
Trigger: sse.New(sse.Config{}) with no Handler field, or sse.New() followed by code that expected a default — there is no default Handler.
Common situations: Building an SSE endpoint and forgetting to wire the Handler; refactoring that moved the streaming logic into a separate function but never assigned it to Config.Handler; copying a Config struct where Handler was left nil.
Related errors
- [session] AbsoluteTimeout must be greater than or equal to…
- add: invalid http method
- basicauth: charset must be UTF-8
- [CORS] Invalid origin format after normalization:
- [CORS] Invalid origin format in configuration:
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/61807293d696957f.
Report an issue: GitHub.
Appendix: source
Thrown at middleware/sse/sse.go:27
import (
"bufio"
"context"
"errors"
"fmt"
"sync"
"time"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/utils/v2"
)
var errStreamClosed = errors.New("sse: stream closed")
// New creates a new SSE handler.
func New(config ...Config) fiber.Handler {
cfg := configDefault(config...)
if cfg.Handler == nil {
panic("sse: Handler must not be nil")
}
return func(c fiber.Ctx) error {
c.Set(fiber.HeaderContentType, fiber.MIMETextEventStream)
c.Set(fiber.HeaderCacheControl, "no-cache")
c.Set(fiber.HeaderConnection, "keep-alive")
c.Set("X-Accel-Buffering", "no")
streamContext := c.Context()
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 {View on GitHub (pinned to a105acad6c)