screenpipe/screenpipe · warning
serialize eval request
Error message
serialize eval request
What it means
Bridge::eval serializes a WsEvalRequest to JSON before sending over the WebSocket transport and unwraps with .expect("serialize eval request"). serde_json::to_string can only fail if the value contains non-string map keys or an IO error on the internal writer — impossible for this struct with &str fields, so it is effectively an infallible invariant assertion that panics only if the struct gains a non-serializable field.
Source
Thrown at crates/screenpipe-connect/src/connections/browser/bridge.rs:178
) -> Result<EvalResult, EvalError> {
// Snapshot the transport — if we lose it after this point, the send
// will fail and we'll report it cleanly.
let transport = {
let guard = self.transport.read().await;
guard.as_ref().cloned().ok_or(EvalError::NotConnected)?
};
let id = uuid::Uuid::new_v4().to_string();
let (tx, rx) = oneshot::channel();
self.pending.lock().await.insert(id.clone(), tx);
let frame = serde_json::to_string(&WsEvalRequest {
id: &id,
action: "eval",
code,
url,
})
.expect("serialize eval request");
if let Err(e) = transport.send_text(frame).await {
self.pending.lock().await.remove(&id);
// The transport is dead — clear it so /status reflects reality.
self.detach_transport(&transport).await;
return Err(EvalError::SendFailed(e));
}
match tokio::time::timeout(timeout, rx).await {
Ok(Ok(result)) => Ok(result),
Ok(Err(_)) => Err(EvalError::Disconnected),
Err(_) => {
self.pending.lock().await.remove(&id);
Err(EvalError::Timeout(timeout.as_secs()))
}
}
}
View on GitHub (pinned to 4ebf712990)
Solutions
- propagate serialization as an EvalError::Serialize variant instead of panicking
- keep WsEvalRequest fields as strings/primitives that serde_json can never fail on
- add a unit test serializing the request so regressions surface in CI
Example fix
// before
serde_json::to_string(&WsEvalRequest { ... }).expect("serialize eval request");
// after
let frame = serde_json::to_string(&WsEvalRequest { ... })
.map_err(|e| EvalError::Serialize(e))?; Defensive patterns
Strategy: try-catch
Try / catch
let frame = serde_json::to_string(&request)
.map_err(|e| EvalError::Serialize(e))?; Prevention
- keep wire structs to String/&str/primitive fields so serde_json serialization is infallible
- add a serialization unit test for WsEvalRequest
- return a dedicated Serialize error variant instead of .expect in async request paths
When it happens
Trigger: adding a field to WsEvalRequest whose serialization can fail (e.g. a map with non-string keys) or replacing serde_json with a fallible serializer; a code change introducing a poison value into `code`/`url` is not a real trigger since they are &str.
Common situations: schema evolution of the bridge protocol; swapping the JSON library for one with stricter constraints.
Related errors
- OAuth client registration returned invalid JSON: {}
- OAuth refresh endpoint returned invalid JSON: {}
- parsing recording settings from {}: {e}
- recording settings did not serialize to an object
- failed to parse {} as live-view-template.v1: {error}
AI-assisted analysis of screenpipe/screenpipe@4ebf712990 (2026-09-01).
Data as JSON: /api/errors/719f0f8002ea3e6c.
Report an issue: GitHub.