{"record":{"id":"e963ef62f8117dac","repo":"gofiber/fiber","slug":"sse-invalid-id-w","errorCode":null,"errorMessage":"sse: invalid id: %w","messagePattern":"sse: invalid id: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"middleware/sse/event.go","lineNumber":44,"sourceCode":"\t// Name sets the SSE event field.\n\tName string\n\n\t// Retry sets the SSE retry field for this event.\n\tRetry time.Duration\n}\n\nfunc writeEvent(w *bufio.Writer, event Event, jsonMarshal ...utils.JSONMarshal) error {\n\tdata, err := eventData(event.Data, jsonMarshalOrDefault(jsonMarshal))\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tvar frame bytes.Buffer\n\n\tif event.ID != \"\" {\n\t\tid, err := sanitizeField(event.ID)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"sse: invalid id: %w\", err)\n\t\t}\n\t\tif id != \"\" {\n\t\t\tappendField(&frame, \"id\", id)\n\t\t}\n\t}\n\tif event.Name != \"\" {\n\t\tname, err := sanitizeField(event.Name)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"sse: invalid event: %w\", err)\n\t\t}\n\t\tif name != \"\" {\n\t\t\tappendField(&frame, \"event\", name)\n\t\t}\n\t}\n\tif event.Retry > 0 {\n\t\tappendField(&frame, \"retry\", utils.FormatInt(event.Retry.Milliseconds()))\n\t}\n\tif data.hasData {","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/gofiber/fiber/blob/a105acad6c1e4576a77f01e02973f67e962bb58d/middleware/sse/event.go#L26-L62","documentation":"Thrown by writeEvent when sanitizeField rejects the Event.ID value because it contains a carriage return (\\r) or line feed (\\n). SSE frames are newline-delimited on the wire, so a CR/LF in the id field would prematurely terminate or corrupt the frame; the library refuses to emit malformed data and returns errInvalidField wrapped as 'sse: invalid id'.","triggerScenarios":"Calling stream.Event(...) / writeEvent with an Event whose ID contains a newline or carriage return — e.g. an ID built from multi-line user input, a base64-with-newlines blob, or a copied string that includes a trailing \\n.","commonSituations":"Echoing an untrusted Last-Event-ID header verbatim into a new event.ID; pasting multi-line identifiers; IDs derived from logs or stack traces that contain newlines.","solutions":["Strip CR/LF (and ideally all control characters) from the ID before building the Event.","Use single-line, newline-free identifiers (UUIDs, numeric counters, hex hashes).","If you must round-trip arbitrary data, encode it (base64 without newlines, hex) before using as the ID."],"exampleFix":"// before\nstream.Event(sse.Event{ID: multilineInput, Data: payload})\n// -> sse: invalid id: field must not contain CR or LF\n\n// after\nid := strings.NewReplacer(\"\\r\", \"\", \"\\n\", \"\").Replace(multilineInput)\nstream.Event(sse.Event{ID: id, Data: payload})","handlingStrategy":"validation","validationCode":"func safeSSEID(id string) string {\n    return strings.NewReplacer(\"\\r\", \"\", \"\\n\", \"\").Replace(id)\n}\n// then: stream.Event(sse.Event{ID: safeSSEID(rawID), Data: payload})","typeGuard":"func isValidSSEField(s string) bool {\n    return !strings.ContainsAny(s, \"\\r\\n\")\n}","tryCatchPattern":"id := safeSSEID(rawID)\nif err := stream.Event(sse.Event{ID: id, Data: payload}); err != nil {\n    return // a field-validation or write error ends the stream\n}","preventionTips":["Never echo raw Last-Event-ID or user input into Event.ID without sanitizing.","Prefer UUIDs / counters / hex hashes as IDs.","Strip CR, LF (and ideally all C0 controls) from any ID you did not generate.","Add a unit test that feeds multi-line strings into your event builder."],"tags":["sse","validation","wire-format"],"backgroundTag":null,"analyzedSha":"a105acad6c1e4576a77f01e02973f67e962bb58d","analyzedAt":"2026-08-11T17:33:26.942Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}