gofiber/fiber · warning · errInvalidField
field must not contain CR or LF
Error message
field must not contain CR or LF
What it means
Declared as errInvalidField in sse/event.go and returned (wrapped as 'sse: invalid id' / 'sse: invalid event') by writeEvent when an Event.ID or Event.Name contains a carriage return or line feed. SSE frames are delimited by line breaks, so a CR/LF in a single-line field would let attacker-controlled data inject additional fields/events — a response-splitting/injection vector. sanitizeField rejects the whole event rather than silently stripping.
Source
Thrown at middleware/sse/event.go:15
package sse
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
"github.com/gofiber/utils/v2"
)
var errInvalidField = errors.New("field must not contain CR or LF")
// Event defines a single Server-Sent Event frame.
type Event struct {
// Data is written as one or more data fields. Strings and byte slices are
// written as-is; other values are JSON encoded.
Data any
// ID sets the SSE id field.
ID string
// 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 {View on GitHub (pinned to 9a4c7e57fe)
Solutions
- Strip/validate CR and LF from any id/name before building the Event (the data field may contain newlines; id/event may not).
- Treat the wrapped error as fatal for that frame and drop or log it rather than retrying with the same value.
- Source-filter: reject or sanitize upstream inputs that populate Event.ID / Event.Name.
Example fix
// before
stream.Event(sse.Event{ID: lastEventID, Name: topic, Data: payload})
// after — sanitize single-line fields
id := strings.NewReplacer("\r", "", "\n", "").Replace(lastEventID)
topic := strings.NewReplacer("\r", "", "\n", "").Replace(topic)
stream.Event(sse.Event{ID: id, Name: topic, Data: payload}) Defensive patterns
Strategy: validation
Validate before calling
// Strip CR/LF from any value used as Event.ID or Event.Name before building the event.
func sseField(s string) string {
return strings.NewReplacer("\r", "", "\n", "").Replace(s)
}
stream.Event(sse.Event{ID: sseField(id), Name: sseField(name), Data: payload}) Try / catch
if err := stream.Event(ev); err != nil {
if strings.Contains(err.Error(), "field must not contain CR or LF") {
// id/name had an embedded newline — drop the frame
return nil
}
return err
} Prevention
- Never put raw user input into Event.ID or Event.Name — sanitize first.
- Remember Event.Data MAY contain newlines; Event.ID and Event.Name may not.
- Echoing Last-Event-ID back into Event.ID is the most common cause — sanitize it.
When it happens
Trigger: Calling stream.Event(sse.Event{ID: '...\n...', ...}) or setting Event.Name to a value containing \r or \n — typically because the id/name came from an un-sanitized user input (e.g. Last-Event-ID echo, a username used as an event name, or a database value with embedded newlines).
Common situations: Echoing client-supplied Last-Event-ID into the next event's id; using user display names or record fields as event names; CRLF line endings from Windows-edited content bleeding into event metadata.
Related errors
- invalid path
- sse: invalid id: %w
- sse: invalid event: %w
- tls: AutoCertManager cannot be combined with CertFile/CertKe
- log: context tag name and function are required
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/088d70389347c6f6.json.
Report an issue: GitHub.