DioxusLabs/dioxus · error

Failed to serialize SSE event

Error message

Failed to serialize SSE event

What it means

ServerEvents::from_stream maps every item of the user's TryStream through axum's Event::json_data. json_data returns Err when serde_json cannot serialize the event (custom Serialize impls that fail, maps with non-string keys, invalid nested payloads) and the closure unwraps it with expect, so one bad event panics the stream task.

Source

Thrown at packages/fullstack/src/payloads/sse.rs:318

            Self {
                _marker: std::marker::PhantomData,
                client: None,
                keep_alive: Some(KeepAlive::new().interval(Duration::from_secs(15))),
                sse: Some(sse),
            }
        }

        /// Create a `ServerEvents` from a `TryStream` of events.
        pub fn from_stream<S>(stream: S) -> Self
        where
            S: TryStream<Ok = T, Error = BoxError> + Send + 'static,
            T: Serialize,
        {
            let stream = stream.map_ok(|event| {
                axum::response::sse::Event::default()
                    .json_data(event)
                    .expect("Failed to serialize SSE event")
            });
            let sse = axum::response::Sse::new(stream.boxed());
            Self {
                _marker: std::marker::PhantomData,
                client: None,
                keep_alive: Some(KeepAlive::new().interval(Duration::from_secs(15))),
                sse: Some(sse),
            }
        }

        /// Set the keep-alive configuration for the SSE connection.
        ///
        /// A `None` value will disable the default `KeepAlive` of 15 seconds.
        pub fn with_keep_alive(mut self, keep_alive: Option<KeepAlive>) -> Self {
            self.keep_alive = keep_alive;
            self
        }

View on GitHub (pinned to 393d190a80)

Solutions

  1. Fix the event type: use string keys (HashMap<String, _>, BTreeMap) and derive Serialize where possible
  2. Pre-test representative events with serde_json::to_string before wiring them into the stream
  3. For dynamic payloads, send pre-serialized JSON via ServerEvents::new + SseTx instead of from_stream
  4. Add unit tests that serialize every event variant the stream can emit

Example fix

// before
let events = ServerEvents::from_stream(
    stream.map_ok(|ev: HashMap<u32, String>| ev), // non-string keys -> serde_json error
);
// after
let events = ServerEvents::from_stream(
    stream.map_ok(|ev: HashMap<String, String>| ev),
);
Defensive patterns

Strategy: validation

Validate before calling

// Smoke-test the event type before wiring the stream:
fn can_serialize<T: Serialize>(event: &T) -> bool {
    serde_json::to_string(event).is_ok()
}
assert!(can_serialize(&sample_event));

Try / catch

// Send pre-serialized events via SseTx, handling failures explicitly:
ServerEvents::new(move |tx| async move {
    while let Some(ev) = rx.next().await {
        match serde_json::to_string(&ev) {
            Ok(json) => { tx.send(json); }
            Err(e) => { tracing::error!("skipping unserializable event: {e}"); }
        }
    }
})

Prevention

When it happens

Trigger: Streaming a type T through ServerEvents::from_stream where T's Serialize errors at runtime: HashMap<u32, _> or other non-string-keyed maps, hand-written Serialize impls returning Err, or types that encode invalid JSON in edge cases.

Common situations: Server-function SSE endpoints returning dynamic/aggregate payloads; switching an event struct to a map keyed by numeric ids; custom Serialize impls that can fail on edge-case state.

Related errors


AI-assisted analysis of DioxusLabs/dioxus@393d190a80 (2026-08-16). Data as JSON: /api/errors/e9aa2f960d899889. Report an issue: GitHub.