gofiber/fiber · warning
sse: invalid id: %w
Error message
sse: invalid id: %w
What it means
writeEvent rejects an Event.ID that contains a carriage return or line feed: in the SSE wire format a newline terminates a field, so an embedded CR/LF would corrupt the id field. sanitizeField returns errInvalidField and Fiber wraps it rather than emitting a broken frame.
Source
Thrown at middleware/sse/event.go:44
// Name sets the SSE event field.
Name string
// Retry sets the SSE retry field for this event.
Retry time.Duration
}
func writeEvent(w *bufio.Writer, event Event, jsonMarshal ...utils.JSONMarshal) error {
data, err := eventData(event.Data, jsonMarshalOrDefault(jsonMarshal))
if err != nil {
return err
}
var frame bytes.Buffer
if event.ID != "" {
id, err := sanitizeField(event.ID)
if err != nil {
return fmt.Errorf("sse: invalid id: %w", err)
}
if id != "" {
appendField(&frame, "id", id)
}
}
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 {View on GitHub (pinned to 9a4c7e57fe)
Solutions
- Strip or replace CR and LF from the id before building the Event.
- Validate that the id is a single line and reject/log multi-line values at the source.
Example fix
// before
stream.Event(sse.Event{ID: rawID, Data: payload}) // rawID may contain \n
// after
stream.Event(sse.Event{ID: sanitizeSSEField(rawID), Data: payload})
func sanitizeSSEField(s string) string {
s = strings.ReplaceAll(s, "\r\n", "-")
s = strings.ReplaceAll(s, "\r", "-")
return strings.ReplaceAll(s, "\n", "-")
} Defensive patterns
Strategy: validation
Validate before calling
func validSSEID(id string) bool {
return !strings.ContainsAny(id, "\r\n")
}
// before sending:
if !validSSEID(event.ID) {
event.ID = strings.NewReplacer("\r\n", "-", "\r", "-", "\n", "-").Replace(event.ID)
} Try / catch
if err := stream.Event(ev); err != nil {
if errors.Is(err, sse.ErrInvalidField) { // if exposed, else string-match
ev.ID = sanitizeSSEField(ev.ID)
return stream.Event(ev)
}
} Prevention
- Never trust external strings as SSE id/event fields without sanitizing newlines.
- Generate ids from single-line sources (UUID, counter, base64 RawStdEncoding).
When it happens
Trigger: Passing sse.Event{ID: value} where value contains \n or \r - e.g. a multi-line string, base64 with line breaks, or unsanitized user input used as the last-event id.
Common situations: Using database/external values verbatim as the SSE id; copy-pasting multi-line identifiers; treating a free-text field as an id.
Related errors
- sse: invalid event: %w
- log: context tag name and function are required
- field must not contain CR or LF
- sse: write event: %w
- sse: write heartbeat: %w
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/e963ef62f8117dac.json.
Report an issue: GitHub.