{"record":{"id":"60ff0520c44897b1","repo":"nautechsystems/nautilus_trader","slug":"heartbeat-interval-cannot-be-zero","errorCode":null,"errorMessage":"Heartbeat interval cannot be zero","messagePattern":"Heartbeat interval cannot be zero","errorType":"validation","errorClass":"TransportError::Io(std::io::Error)","httpStatus":null,"severity":"error","filePath":"crates/network/src/websocket/client.rs","lineNumber":228,"sourceCode":"        clippy::unused_async_trait_impl,\n        reason = \"async signature for consistency with connect-based constructors\"\n    )]\n    pub async fn new_with_writer(\n        config: WebSocketConfig,\n        writer: MessageWriter,\n    ) -> Result<Self, TransportError> {\n        Self::new_with_writer_and_state_sink(config, writer, None)\n    }\n\n    fn new_with_writer_and_state_sink(\n        mut config: WebSocketConfig,\n        writer: MessageWriter,\n        state_sink: Option<SocketStateSink>,\n    ) -> Result<Self, TransportError> {\n        install_cryptographic_provider();\n\n        if config.heartbeat_interval_secs == Some(0) {\n            return Err(TransportError::Io(std::io::Error::new(\n                std::io::ErrorKind::InvalidInput,\n                \"Heartbeat interval cannot be zero\",\n            )));\n        }\n\n        let connection_mode = Arc::new(AtomicU8::new(ConnectionMode::Reconnect.as_u8()));\n        let connection_epoch = Arc::new(AtomicU64::new(0));\n        let state_notify = Arc::new(tokio::sync::Notify::new());\n        let controller_notify = Arc::new(tokio::sync::Notify::new());\n        let reconnect_published = Arc::new(AtomicBool::new(true));\n        let outcome =\n            ConnectionMode::complete_reconnect_with_sink(&connection_mode, state_sink.as_ref());\n        debug_assert_eq!(outcome, ReconnectOutcome::Reconnected);\n\n        // Note: We don't spawn a read task here since the reader is handled externally\n        let read_task = None;\n        let read_fence = None;\n","sourceCodeStart":210,"sourceCodeEnd":246,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/network/src/websocket/client.rs#L210-L246","documentation":"The WebSocket client validates config invariants at construction. A heartbeat interval of exactly `Some(0)` seconds is rejected with `InvalidInput` because a zero-period heartbeat timer is meaningless (it would fire every loop iteration or never schedule correctly).","triggerScenarios":"Building `WebSocketConfig` (often by struct literal, bypassing the builder) with `heartbeat_interval_secs: Some(0)` and passing it to `new_with_writer_and_state_sink`.","commonSituations":"Users intending 'no heartbeat' setting 0 instead of `None`, or computing the interval from a config value that defaults to 0 when unset.","solutions":["Use `None` to disable heartbeats instead of `Some(0)`.","Set a positive interval such as `Some(15)` or `Some(30)` seconds.","Clamp the value when loading from config: treat 0 as disabled."],"exampleFix":"// before\nlet config = WebSocketConfig { heartbeat_interval_secs: Some(0), .. };\n// after\nlet config = WebSocketConfig { heartbeat_interval_secs: Some(15), .. }; // or None to disable","handlingStrategy":"validation","validationCode":"fn sane_heartbeat(secs: Option<u64>) -> Option<u64> {\n    match secs { Some(0) | None => None, s => s } // 0 means disabled\n}\n// then: heartbeat_interval_secs: sane_heartbeat(raw_value)","typeGuard":null,"tryCatchPattern":"match WebSocketClient::new_with_writer_and_state_sink(...) {\n    Err(e) if e.to_string().contains(\"Heartbeat interval cannot be zero\") => {\n        eprintln!(\"config error: use None to disable heartbeat\");\n        return;\n    }\n    Err(e) => return Err(e),\n    Ok(c) => c,\n}","preventionTips":["Represent 'disabled' as None, never Some(0).","Clamp 0 from external config files to None at load time.","Prefer the builder API so invariants are enforced early."],"tags":["websocket","validation","rust"],"backgroundTag":"invalid-config-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}