gofiber/fiber · error
sse: marshal data: %w
Error message
sse: marshal data: %w
What it means
When Event.Data is not nil/string/[]byte/json.RawMessage, Fiber JSON-encodes it (via json.Marshal or a custom JSONMarshal). This error means the value cannot be marshaled to JSON: it contains a channel, func, complex number, a custom MarshalJSON that returns an error, or a cyclic structure.
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 9a4c7e57fe)
Solutions
- Only pass JSON-serializable values as Event.Data, or pass raw bytes/json.RawMessage for full control.
- Pre-marshal the value yourself and pass []byte to bypass Fiber's marshal step.
- Fix any custom MarshalJSON or app.Config.JSONEncoder that returns errors.
Example fix
// before
stream.Event(sse.Event{Data: job}) // job contains a chan/func or bad MarshalJSON
// after
raw, err := json.Marshal(job)
if err != nil { return err }
stream.Event(sse.Event{Data: json.RawMessage(raw)}) Defensive patterns
Strategy: validation
Validate before calling
// pre-marshal so errors surface before you touch the stream
raw, err := json.Marshal(payload)
if err != nil {
return fmt.Errorf("event payload not serializable: %w", err)
}
event.Data = json.RawMessage(raw) Type guard
// typeGuard: reject known-unserializable kinds before sending.
func jsonSerializable(v any) bool {
if v == nil { return true }
switch reflect.TypeOf(v).Kind() {
case reflect.Chan, reflect.Func, reflect.UnsafePointer,
reflect.Complex64, reflect.Complex128:
return false
}
return true
} Try / catch
if err := stream.Event(ev); err != nil {
if strings.Contains(err.Error(), "sse: marshal data") {
raw, mErr := json.Marshal(ev.Data)
if mErr != nil { return mErr }
ev.Data = json.RawMessage(raw)
return stream.Event(ev)
}
} Prevention
- Never put chan/func/complex values in Event.Data.
- Pre-marshal to []byte/json.RawMessage when unsure.
- Unit-test JSON marshaling of payload types.
When it happens
Trigger: Passing sse.Event{Data: make(chan int)}, a struct with a func field, a value whose MarshalJSON errors, or a custom JSONEncoder that fails; or an unmarshalable nested field.
Common situations: Accidentally putting a non-serializable Go value as event data; custom MarshalJSON that errors on edge states; a buggy custom JSONEncoder set on the app.
Related errors
- paginate: failed to encode cursor values
- cache: failed to unmarshal key %q: %w
- cache: failed to marshal key %q: %w
- ErrCursorEncode
- failed to decode session data: %w
AI-assisted analysis of gofiber/fiber@9a4c7e57fe (2026-08-04).
Data as JSON: /data/errors/2555eb3023c151a7.json.
Report an issue: GitHub.