{"record":{"id":"07472e858d460b07","repo":"gofiber/fiber","slug":"sse-write-retry-w","errorCode":null,"errorMessage":"sse: write retry: %w","messagePattern":"sse: write retry: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"middleware/sse/sse.go","lineNumber":161,"sourceCode":"\treturn s.write(func(w *bufio.Writer) error {\n\t\treturn writeComment(w, comment)\n\t})\n}\n\n// Retry writes an SSE retry field and flushes it to the client.\nfunc (s *Stream) Retry(retry time.Duration) error {\n\tif retry <= 0 {\n\t\treturn nil\n\t}\n\treturn s.write(func(w *bufio.Writer) error {\n\t\t// Assemble the whole field in a fixed-size scratch and issue one\n\t\t// write: no fmt boxing, and a single error branch.\n\t\tvar scratch [32]byte\n\t\tframe := append(scratch[:0], \"retry: \"...)\n\t\tframe = utils.AppendInt(frame, retry.Milliseconds())\n\t\tframe = append(frame, '\\n', '\\n')\n\t\tif _, err := w.Write(frame); err != nil {\n\t\t\treturn fmt.Errorf(\"sse: write retry: %w\", err)\n\t\t}\n\t\treturn nil\n\t})\n}\n\nfunc (s *Stream) write(fn func(w *bufio.Writer) error) error {\n\ts.mu.Lock()\n\tdefer s.mu.Unlock()\n\n\tif s.err != nil {\n\t\treturn s.err\n\t}\n\tif s.isClosed {\n\t\treturn errStreamClosed\n\t}\n\tif err := fn(s.w); err != nil {\n\t\treturn s.failLocked(err)\n\t}","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/sse/sse.go#L143-L179","documentation":"Thrown by Stream.Retry when writing the 'retry: <ms>\\n\\n' frame to the writer fails. Retry is typically called once at stream start (when cfg.Retry > 0) to tell the client how long to wait before reconnecting. A write failure here means the connection was already broken when the stream tried to establish the retry hint.","triggerScenarios":"The client disconnected or a proxy reset the connection in the narrow window between stream creation and the initial retry-field write; the underlying connection was never successfully established.","commonSituations":"Client that opens then immediately closes the EventSource; intermediary rejecting the stream; races where the connection drops during response setup.","solutions":["Treat a retry-write failure as an already-dead stream; return immediately (the middleware sets streamErr and runs OnClose).","Don't treat this as transient or retry manually — the stream is closed by failLocked.","Verify the reverse proxy allows long-lived SSE connections.","Consider setting Retry only when you know the client supports reconnection semantics."],"exampleFix":"// before\nif err := stream.Retry(3*time.Second); err != nil { log.Error(err); /* continue writing */ }\n// after\nif err := stream.Retry(3*time.Second); err != nil {\n    return // stream is closed, further writes will fail with errStreamClosed\n}","handlingStrategy":"try-catch","validationCode":"// Not locally preventable (transport), but only set Retry when the client needs it.\nif clientSupportsReconnect {\n    cfg.Retry = 3 * time.Second\n}","typeGuard":null,"tryCatchPattern":"if err := stream.Retry(cfg.Retry); err != nil {\n    return // connection already dead; stream is closed\n}","preventionTips":["Treat a Retry-write error as terminal — failLocked closes the stream.","Confirm the reverse proxy permits long-lived SSE before setting Retry.","Don't retry Retry(); the stream's isClosed flag will reject subsequent writes."],"tags":["sse","network","write","retry","disconnected"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}