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

  1. Strip/validate CR and LF from any id/name before building the Event (the data field may contain newlines; id/event may not).
  2. Treat the wrapped error as fatal for that frame and drop or log it rather than retrying with the same value.
  3. 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

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


AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04). Data as JSON: /data/errors/088d70389347c6f6.json. Report an issue: GitHub.