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

  1. Strip or replace CR and LF from the id before building the Event.
  2. 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

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


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