gofiber/fiber · info
sse: write heartbeat: %w
Error message
sse: write heartbeat: %w
What it means
The SSE heartbeat (an empty comment ':\n\n') could not be written to the response stream. Heartbeats are emitted on a timer by startHeartbeat to keep the connection alive; a failure means the client has disconnected or the connection broke.
Source
Thrown at middleware/sse/event.go:76
}
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 {
return fmt.Errorf("sse: finish comment: %w", err)
}
return nil
}
type eventPayload struct {
data string
hasData bool
}View on GitHub (pinned to 9a4c7e57fe)
Solutions
- Heartbeat write failures already stop the heartbeat goroutine internally; ensure your handler also observes stream.Done() and exits.
- Make heartbeat interval shorter than the proxy idle timeout so the link stays open while the client is alive.
- Handle stream closure gracefully in the main handler loop.
Defensive patterns
Strategy: validation
Validate before calling
// choose heartbeat < proxy idle timeout
app.Use(sse.New(sse.Config{
Handler: sseHandler,
HeartbeatInterval: 10 * time.Second,
})) Try / catch
// heartbeat failures are handled internally; observe stream end in your handler.
go func() {
<-stream.Done()
cancel() // unblock your producer
}() Prevention
- Set HeartbeatInterval below your reverse-proxy idle timeout.
- Don't hold resources after stream.Done() closes.
When it happens
Trigger: The heartbeat ticker fires after the client closed the connection; network drop during an otherwise-idle SSE connection; proxy closed the idle link.
Common situations: Idle SSE connections behind strict proxies; clients that sleep/suspend; mobile network changes.
Related errors
- sse: write event: %w
- sse: write comment: %w
- sse: finish comment: %w
- sse: write retry: %w
- cache: failed to get key %q from storage: %w
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/cf0c96761cb3638b.json.
Report an issue: GitHub.