{"record":{"id":"f32a4250894d5ab4","repo":"nautechsystems/nautilus_trader","slug":"polymarketrtdscryptotwap-metadata-window-seconds","errorCode":null,"errorMessage":"PolymarketRtdsCryptoTwap metadata['window_seconds'] must be 30 or 60, received {other}","messagePattern":"PolymarketRtdsCryptoTwap metadata\\['window_seconds'\\] must be 30 or 60, received (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/rtds.rs","lineNumber":253,"sourceCode":"        }\n    }\n\n    const fn topic(self) -> RtdsTopic {\n        match self {\n            Self::ThirtySeconds => RtdsTopic::CryptoPricesTwapThirty,\n            Self::SixtySeconds => RtdsTopic::CryptoPricesTwapSixty,\n        }\n    }\n}\n\nimpl TryFrom<u64> for RtdsCryptoTwapWindow {\n    type Error = anyhow::Error;\n\n    fn try_from(value: u64) -> Result<Self, Self::Error> {\n        match value {\n            30 => Ok(Self::ThirtySeconds),\n            60 => Ok(Self::SixtySeconds),\n            other => anyhow::bail!(\n                \"PolymarketRtdsCryptoTwap metadata['window_seconds'] must be 30 or 60, received {other}\"\n            ),\n        }\n    }\n}\n\n#[derive(Clone, Copy)]\nenum TimestampGuard {\n    // Snapshots can replay, so drop points at or before the high-water mark.\n    Snapshot,\n    // Live updates never replay, so drop only strictly-older points.\n    Live,\n}\n\n#[derive(Clone, Copy, Debug)]\npub(crate) enum ReconcileReason {\n    DesiredChanged,\n    EnsureConnected,","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/rtds.rs#L235-L271","documentation":"TryFrom<u64> for RtdsCryptoTwapWindow: the RTDS crypto TWAP metadata window_seconds is neither 30 nor 60, the only TWAP windows Polymarket's real-time stream publishes, so the metadata cannot be deserialized into a valid topic.","triggerScenarios":"RTDS metadata advertises a window_seconds value other than 30 or 60 (new interval added upstream, corrupted metadata, or misconfigured subscription), and the conversion runs.","commonSituations":"Polymarket adding a new TWAP interval before this adapter supports it; hand-edited subscription config; version drift between the adapter and the live RTDS API.","solutions":["Upgrade the nautilus_polymarket adapter to a version supporting the advertised window","Restrict subscriptions to 30s/60s TWAP channels","Validate metadata['window_seconds'] in (30, 60) before constructing the TWAP type"],"exampleFix":"// before\nlet window = PolymarketRtdsCryptoTwap::try_from(15u64)?; // panics/bails\n// after\nlet window = PolymarketRtdsCryptoTwap::try_from(30u64)?;","handlingStrategy":"type-guard","validationCode":"fn supported_twap_window(w: u64) -> bool { w == 30 || w == 60 }","typeGuard":"fn as_twap_window(w: u64) -> Option<u64> {\n    matches!(w, 30 | 60).then_some(w)\n}","tryCatchPattern":"match PolymarketRtdsCryptoTwap::try_from(window_seconds) {\n    Err(e) => { log::error!(\"unsupported TWAP window: {e}\"); return; }\n    Ok(w) => w,\n}","preventionTips":["Pin subscriptions to known 30s/60s TWAP channels","Upgrade the adapter when Polymarket adds new intervals","Validate upstream metadata before conversion"],"tags":["rust","rtds","validation","enum"],"backgroundTag":"value-out-of-range","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"}