nautechsystems/nautilus_trader · error · anyhow::Error
invalid RTDS JSON frame
Error message
invalid RTDS JSON frame
What it means
The Polymarket RTDS (real-time data socket) handler parses each incoming text frame as an RtdsEnvelope. If JSON deserialization fails AND the frame looks like a genuine RTDS message (per malformed_frame_requires_visible_twap_failure), the error is surfaced as "invalid RTDS JSON frame"; frames that don't even resemble RTDS payloads are silently ignored at debug level. This error means a real RTDS frame arrived but its JSON did not match the expected envelope schema.
Source
Thrown at crates/adapters/polymarket/src/rtds.rs:1151
if self.clear_ws_if_current(&ws) {
self.request_reconcile(ReconcileReason::TransportReset);
}
break;
}
}
}
}
fn handle_text_message(&self, text: &str) -> anyhow::Result<()> {
if text.trim().is_empty() {
return Ok(());
}
let envelope: RtdsEnvelope = match serde_json::from_str(text) {
Ok(envelope) => envelope,
Err(e) => {
if self.malformed_frame_requires_visible_twap_failure(text) {
return Err(anyhow::Error::new(e).context("invalid RTDS JSON frame"));
}
log::debug!("Ignoring non-RTDS JSON frame: {e}");
return Ok(());
}
};
self.handle_envelope(&envelope)
}
fn handle_envelope(&self, envelope: &RtdsEnvelope) -> anyhow::Result<()> {
match (envelope.topic.as_str(), envelope.msg_type.as_str()) {
("crypto_prices", "subscribe") => {
self.handle_crypto_price_subscribe(envelope);
}
("crypto_prices", "update") => {
self.handle_crypto_price_update(envelope);
}
("crypto_prices_twap_thirty", "update") => {View on GitHub (pinned to 18893faf8b)
Solutions
- Log the offending raw text and compare it to the RtdsEnvelope struct to find the schema drift.
- Update the nautilus OKX/Polymarket adapter (and its RTDS types) to the version matching the current Polymarket protocol.
- If a new event variant is the cause, extend RtdsEnvelope (e.g. #[serde(tag)] untagged variants) to accept it.
- Pin the Polymarket service version if a server-side rollout broke compatibility.
- Check for intermediaries (proxies) corrupting the frame payload.
Example fix
// before
#[derive(Deserialize)]
struct RtdsEnvelope { event_type: String, payload: serde_json::Value }
// after
#[derive(Deserialize)]
#[serde(untagged)]
enum RtdsEnvelope { Known { event_type: String, payload: serde_json::Value }, Unknown(serde_json::Value) } Defensive patterns
Strategy: type-guard
Validate before calling
// peek at frame before full parse
let v: serde_json::Value = serde_json::from_str(text)?;
if v.get("type").is_none() { return Ok(()); } // not an RTDS frame Type guard
fn is_rtds_envelope(v: &serde_json::Value) -> bool {
v.get("type").and_then(|t| t.as_str()).is_some()
&& v.get("payload").map_or(false, |p| p.is_object())
} Try / catch
match handler.handle_frame(text) {
Ok(()) => {}
Err(e) if e.to_string().contains("invalid RTDS JSON frame") => {
error!("RTDS schema drift: {e}; raw={text}");
alert_and_reconnect();
}
Err(e) => return Err(e),
} Prevention
- Keep the adapter updated with Polymarket RTDS protocol changes
- Log raw frames that fail parsing to detect schema drift early
- Use serde untagged/lenient variants for unknown event types
- Add a CI test deserializing recorded live RTDS samples
When it happens
Trigger: Receiving an RTDS WebSocket message whose JSON shape does not match RtdsEnvelope (missing/renamed fields, unexpected event type, non-string fields where strings are expected), and the frame heuristically requires a visible failure (e.g. it affects TWAP handling).
Common situations: Polymarket changing/adding RTDS event schemas after an adapter upgrade; subscribing to a channel producing a message variant the adapter doesn't model; a proxy or gateway mangling/re-truncating frames; version mismatch between adapter and current RTDS protocol.
Understand the failure class
Background: "Invalid JSON response" and "Failed to parse response" errors: when an API answers 200 but the body isn't the JSON your library expected — this error's family across 28 libraries.
Related errors
- fee exponent must be a decimal number or numeric string
- unsupported subscribed RTDS message topic={topic} type={msg_
- Unsupported RTDS custom data type: {other}
- failed to send RTDS {action} request: {e}
- invalid RTDS crypto TWAP payload: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/63bf1ef5b87e10a7.
Report an issue: GitHub.