{"record":{"id":"4f049d098423bc60","repo":"nautechsystems/nautilus_trader","slug":"rtds-twap-topic-requires-window-s-receive","errorCode":null,"errorMessage":"RTDS TWAP topic {:?} requires window_s={}, received {}","messagePattern":"RTDS TWAP topic (.+?) requires window_s=(.+?), received (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/rtds.rs","lineNumber":1305,"sourceCode":"\n            self.emit_custom_payload(&custom_payload, data_types.clone());\n        }\n    }\n\n    fn handle_crypto_twap_update(\n        &self,\n        envelope: &RtdsEnvelope,\n        window: RtdsCryptoTwapWindow,\n    ) -> anyhow::Result<()> {\n        let topic = window.topic();\n        if !self.has_topic_subscription(topic.as_str()) {\n            return Ok(());\n        }\n\n        let payload: CryptoTwapPayloadRaw = serde_json::from_str(envelope.payload.get())\n            .map_err(|e| anyhow::anyhow!(\"invalid RTDS crypto TWAP payload: {e}\"))?;\n        if payload.window_s != window.seconds() {\n            anyhow::bail!(\n                \"RTDS TWAP topic {:?} requires window_s={}, received {}\",\n                topic.as_str(),\n                window.seconds(),\n                payload.window_s,\n            );\n        }\n        let symbol_lower = payload.symbol.to_ascii_lowercase();\n        let value =\n            decimal_from_signed_e18(\"full_accuracy_value\", payload.full_accuracy_value.as_str())?;\n        let ts_event = unix_nanos_from_millis(\"payload.timestamp\", payload.timestamp)?;\n        unix_nanos_from_millis(\"envelope.timestamp\", envelope.timestamp)?;\n        let Some(data_types) =\n            self.admit_twap_observation(topic, &symbol_lower, payload.timestamp, value)?\n        else {\n            return Ok(());\n        };\n\n        let ts_init = self.inner.clock.get_time_ns();","sourceCodeStart":1287,"sourceCodeEnd":1323,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/rtds.rs#L1287-L1323","documentation":"Raised when a crypto TWAP message arrives whose payload window_s does not match the window implied by its topic (30 for crypto_prices_twap_thirty, 60 for crypto_prices_twap_sixty). The topic and payload disagree, so trusting the payload would corrupt the price series; the feed validates and bails. This guards against upstream protocol changes or misrouted messages.","triggerScenarios":"RTDS delivers a TWAP message on crypto_prices_twap_thirty with payload.window_s != 30 (or the sixty variant with window_s != 60) — e.g. Polymarket changes window units or routes messages to the wrong topic.","commonSituations":"Upstream API changing TWAP payload semantics; misrouted messages from the publisher; replaying recorded fixtures with mismatched topic/payload pairs.","solutions":["Upgrade the adapter in case upstream changed topic/window semantics and a fix exists.","Capture the full envelope (topic + payload) and report the mismatch to the venue/adapter maintainers.","If replaying recorded data, regenerate fixtures so payload.window_s matches the topic's required window.","As a stopgap, drop the subscription to the offending topic if the data is not required."],"exampleFix":"// before\n// fixture: topic \"crypto_prices_twap_thirty\" with window_s=60\n{\"topic\":\"crypto_prices_twap_thirty\",\"payload\":\"{\\\"window_s\\\":60,...}\"}\n// after\n{\"topic\":\"crypto_prices_twap_thirty\",\"payload\":\"{\\\"window_s\\\":30,...}\"}","handlingStrategy":"validation","validationCode":"fn twap_window_matches(topic: &str, window_s: u64) -> bool {\n    matches!((topic, window_s), (\"crypto_prices_twap_thirty\", 30) | (\"crypto_prices_twap_sixty\", 60))\n}","typeGuard":"fn parse_twap_payload(topic: &str, raw: &str) -> anyhow::Result<CryptoTwapPayloadRaw> {\n    let p: CryptoTwapPayloadRaw = serde_json::from_str(raw)?;\n    let required = if topic.ends_with(\"thirty\") { 30 } else { 60 };\n    anyhow::ensure!(p.window_s == required, \"window_s {} != required {required}\", p.window_s);\n    Ok(p)\n}","tryCatchPattern":"match feed.next_event().await {\n    Err(e) if e.to_string().contains(\"RTDS TWAP topic\") => {\n        log::error!(\"TWAP topic/payload mismatch (upstream protocol change?): {e}\");\n    }\n    other => { /* normal handling */ }\n}","preventionTips":["Validate recorded/replayed fixtures so window_s matches each topic's window.","Track upstream RTDS schema changes for TWAP payloads.","Keep the adapter updated so window semantics stay in sync with the venue.","Treat this error as a data-integrity alarm, not a transient failure — do not auto-retry."],"tags":["websocket","validation","protocol-mismatch","twap","polymarket"],"backgroundTag":"invalid-argument-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}