gofiber/fiber · error
sse: write heartbeat
Error message
sse: write heartbeat: %w
What it means
Thrown by writeComment when writing the heartbeat frame (":\n\n") to the writer fails. The heartbeat is sent to keep the connection alive; a write failure means the underlying connection is broken, identical in cause to 208 but on the heartbeat/comment path.
Solutions
- Treat the error as end-of-stream; stop the heartbeat loop and return.
- Verify HeartbeatInterval is shorter than your proxy's idle timeout.
- Do not swallow and retry; a failed write means the stream is dead.
Example fix
// before
if err := stream.Comment(""); err != nil { log.Error(err) } // keeps trying
// after
if err := stream.Comment(""); err != nil {
return // connection is gone
} Defensive patterns
Strategy: try-catch
Validate before calling
// Heartbeats are infrastructure; nothing to pre-validate.
// Just make sure the interval beats your proxy timeout:
cfg := sse.Config{
HeartbeatInterval: 10 * time.Second, // < proxy idle timeout
DisableHeartbeat: false,
} Try / catch
if err := stream.Comment(""); err != nil {
return // heartbeat write failed => client/proxy dropped the connection
} Prevention
- Keep DisableHeartbeat=false on long streams.
- Set HeartbeatInterval below the smallest idle timeout in your proxy chain.
- Treat heartbeat-write errors as terminal; do not continue.
When it happens
Trigger: The client has disconnected, a proxy reset the connection, or any network write error occurred while emitting the heartbeat or an empty comment.
Common situations: Idle SSE connections dropped by intermediaries between heartbeats; clients closing the browser; mobile network interruptions.
Related errors
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/cf0c96761cb3638b.
Report an issue: GitHub.
Appendix: 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 a105acad6c)