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 from a Config, and the Config.Handler (the function that writes events to the stream) is the only required field. If it is nil the middleware has nothing to execute per connection, so sse.New panics with "sse: Handler must not be nil".

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 9a4c7e57fe)

Solutions

  1. Provide a Config with a non-nil Handler: sse.New(sse.Config{Handler: func(c fiber.Ctx, stream *sse.Stream) error {...}}).
  2. Define the handler as a named function and assign it to Handler to keep config readable.
  3. If you only need the streaming plumbing, still supply a minimal handler that drives your event source.

Example fix

// before
app.Get("/events", sse.New())
// after
app.Get("/events", sse.New(sse.Config{
    Handler: func(c fiber.Ctx, stream *sse.Stream) error {
        return stream.Event(sse.Event{Event: "ping", Data: "hello"})
    },
}))
Defensive patterns

Strategy: validation

Validate before calling

if cfg.Handler == nil {
    log.Fatal("sse: Config.Handler must not be nil")
}
app.Get("/events", sse.New(cfg))

Type guard

func hasSSEHandler(cfg sse.Config) bool {
    return cfg.Handler != nil
}

Prevention

When it happens

Trigger: Calling sse.New() with no config, or with a Config where the Handler field is not set. The default config leaves Handler as nil, so omitting it always triggers this panic.

Common situations: Calling sse.New() bare expecting a default behavior. Building Config incrementally and forgetting to assign Handler. Copying an example that omitted the Handler for brevity.

Related errors


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