gofiber/fiber · error
sse: marshal data
Error message
sse: marshal data: %w
What it means
Thrown by eventData when the Event.Data value is not one of the pass-through types (nil, string, []byte, json.RawMessage) and the configured JSON marshaler fails to encode it. The %w wraps the json.Marshal (or custom JSONMarshal) error. Data values of these special types bypass JSON; everything else is JSON-encoded, so a non-JSON-encodable value triggers this.
Solutions
- Only pass JSON-encodable values as Event.Data.
- For raw/preformatted payloads, pass a string or []byte (these bypass JSON entirely).
- If you use a custom jsonMarshal (via app config or Stream.Event variadic), ensure it handles your types or returns a clear error.
- Implement json.Marshaler correctly on custom types; test MarshalJSON separately.
Example fix
// before
stream.Event(sse.Event{Data: struct{ Cb func() }{}})
// -> sse: marshal data: json: unsupported type: func()
// after — pass a serializable DTO
stream.Event(sse.Event{Data: MyDTO{ID: 1, Name: "x"}})
// or send raw preformatted JSON
stream.Event(sse.Event{Data: []byte(`{"id":1}`)}) Defensive patterns
Strategy: validation
Validate before calling
// Pre-marshal to fail fast with a clear error before hitting the stream.
func mustSSEData(v any) any {
switch v.(type) {
case nil, string, []byte, json.RawMessage:
return v
default:
if _, err := json.Marshal(v); err != nil {
log.Fatalf("Event.Data not JSON-encodable: %v", err)
}
return v
}
} Type guard
func isJSONEncodable(v any) bool {
switch v.(type) {
case nil, string, []byte, json.RawMessage:
return true
}
_, err := json.Marshal(v)
return err == nil
} Try / catch
if !isJSONEncodable(ev.Data) {
ev.Data = []byte(`{"error":"non-serializable payload"}`)
}
if err := stream.Event(ev); err != nil { return } Prevention
- Only pass JSON-encodable values as Event.Data.
- For preformatted payloads, pass string or []byte to bypass JSON.
- Implement and test json.Marshaler on custom types.
- If using a custom JSONMarshal, ensure it handles all your event types.
When it happens
Trigger: Passing Event.Data as a func, channel, complex64/128, a struct with unexported fields of unsupported types, a value implementing json.Marshaler whose MarshalJSON returns an error, or a cyclic structure.
Common situations: Streaming a struct that contains a non-serializable field (e.g. a sync.Mutex, a *sql.DB, a func callback); passing a map with non-string keys; a custom MarshalJSON that errors on edge cases.
Related errors
- fiber: failed to encode shared state
- cache: failed to marshal key
- cache: failed to unmarshal key
- errInvalidField
- errStreamClosed
AI-assisted analysis of gofiber/fiber@a105acad6c (2026-08-11).
Data as JSON: /api/errors/2555eb3023c151a7.
Report an issue: GitHub.
Appendix: source
Thrown at middleware/sse/event.go:109
type eventPayload struct {
data string
hasData bool
}
func eventData(data any, jsonMarshal utils.JSONMarshal) (eventPayload, error) {
switch value := data.(type) {
case nil:
return eventPayload{}, nil
case string:
return eventPayload{data: value, hasData: true}, nil
case []byte:
return eventPayload{data: string(value), hasData: true}, nil
case json.RawMessage:
return eventPayload{data: string(value), hasData: true}, nil
default:
encoded, err := jsonMarshal(value)
if err != nil {
return eventPayload{}, fmt.Errorf("sse: marshal data: %w", err)
}
return eventPayload{data: string(encoded), hasData: true}, nil
}
}
func jsonMarshalOrDefault(jsonMarshal []utils.JSONMarshal) utils.JSONMarshal {
if len(jsonMarshal) > 0 && jsonMarshal[0] != nil {
return jsonMarshal[0]
}
return json.Marshal
}
func appendField(w *bytes.Buffer, field, value string) {
w.WriteString(field) //nolint:errcheck // bytes.Buffer writes never fail.
w.WriteString(": ") //nolint:errcheck // bytes.Buffer writes never fail.
w.WriteString(value) //nolint:errcheck // bytes.Buffer writes never fail.
w.WriteByte('\n') //nolint:errcheck // bytes.Buffer writes never fail.
}View on GitHub (pinned to a105acad6c)