gofiber/fiber · error

sse: write event

Error message

sse: write event: %w

What it means

Thrown by writeEvent when writing the fully-assembled SSE frame to the bufio.Writer (the HTTP response body writer) fails. The %w wraps the underlying network write error. By the time this fires, the frame itself is valid; the problem is the transport — almost always a disconnected or reset client connection.

Solutions

  1. Treat this as a normal stream-termination: stop writing and return; do not retry writes on a broken stream.
  2. After the handler returns, consult stream.Err() / the stream context to decide cleanup.
  3. Ensure your reverse proxy/idle timeouts are longer than your heartbeat interval so intermediaries don't kill idle streams.
  4. Use the heartbeat (DisableHeartbeat=false) so dead connections are detected proactively.

Example fix

// before
for { if err := stream.Event(ev); err != nil { log.Error(err); continue } }
// after
done := stream.Context().Done()
for {
    select {
    case <-done:
        return // client gone, stop cleanly
    default:
        if err := stream.Event(ev); err != nil { return }
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// There is nothing to validate locally; the failure is a dead socket.
// Instead, structure the handler to respect the stream lifecycle:
func streamHandler(c fiber.Ctx, s *sse.Stream) error {
    ctx := s.Context()
    for {
        select {
        case <-ctx.Done():
            return nil // client gone
        case ev := <-events:
            if err := s.Event(ev); err != nil { return nil }
        }
    }
}

Try / catch

if err := stream.Event(ev); err != nil {
    // write failed => connection is gone; stop producing events
    return
}

Prevention

When it happens

Trigger: The client has closed the connection (tab closed, navigation away), an intermediary proxy/load-balancer timed out and reset the stream, a mobile network dropped, or a broken-pipe/EOF occurred during the write.

Common situations: Long-lived SSE streams where the client goes away silently; reverse proxies with short idle timeouts; flaky mobile networks; clients that hard-close without sending a close frame.

Related errors


AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11). Data as JSON: /api/errors/c0f7942c2f2e78b8. Report an issue: GitHub.

Appendix: source

Thrown at middleware/sse/event.go:67

	}
	if event.Name != "" {
		name, err := sanitizeField(event.Name)
		if err != nil {
			return fmt.Errorf("sse: invalid event: %w", err)
		}
		if name != "" {
			appendField(&frame, "event", name)
		}
	}
	if event.Retry > 0 {
		appendField(&frame, "retry", utils.FormatInt(event.Retry.Milliseconds()))
	}
	if data.hasData {
		appendData(&frame, data.data)
	}
	frame.WriteByte('\n') //nolint:errcheck // bytes.Buffer writes never fail.
	if _, err := w.Write(frame.Bytes()); err != nil {
		return fmt.Errorf("sse: write event: %w", err)
	}
	return nil
}

func writeComment(w *bufio.Writer, comment string) error {
	comment = sanitizeComment(comment)
	if comment == "" {
		if _, err := w.WriteString(":\n\n"); err != nil {
			return fmt.Errorf("sse: write heartbeat: %w", err)
		}
		return nil
	}
	for line := range strings.SplitSeq(comment, "\n") {
		if _, err := fmt.Fprintf(w, ": %s\n", line); err != nil {
			return fmt.Errorf("sse: write comment: %w", err)
		}
	}
	if _, err := w.WriteString("\n"); err != nil {

View on GitHub (pinned to a105acad6c)