{"record":{"id":"1662dd40d0bf59f0","repo":"nautechsystems/nautilus_trader","slug":"either-replay-options-or-stream-options-must-b","errorCode":null,"errorMessage":"Either replay `options` or `stream_options` must be provided","messagePattern":"Either replay `options` or `stream_options` must be provided","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/tardis/src/data.rs","lineNumber":511,"sourceCode":"    fn unsubscribe_mark_prices(&mut self, _cmd: &UnsubscribeMarkPrices) -> anyhow::Result<()> {\n        Ok(())\n    }\n\n    fn unsubscribe_index_prices(&mut self, _cmd: &UnsubscribeIndexPrices) -> anyhow::Result<()> {\n        Ok(())\n    }\n\n    fn unsubscribe_funding_rates(&mut self, _cmd: &UnsubscribeFundingRates) -> anyhow::Result<()> {\n        Ok(())\n    }\n\n    async fn connect(&mut self) -> anyhow::Result<()> {\n        if self.is_connected() && self.tasks.is_open() {\n            return Ok(());\n        }\n\n        if self.config.options.is_empty() && self.config.stream_options.is_empty() {\n            anyhow::bail!(\"Either replay `options` or `stream_options` must be provided\");\n        }\n\n        if !self.tasks.is_open() {\n            self.tasks\n                .finish_shutdown(Duration::from_secs(1), Duration::from_secs(2))\n                .await\n                .map_err(|e| anyhow::anyhow!(\"Failed to terminate Tardis tasks: {e}\"))?;\n            self.tasks\n                .start_generation()\n                .map_err(|e| anyhow::anyhow!(\"Failed to start Tardis task generation: {e}\"))?;\n            self.cancellation_token = self.tasks.cancellation_token();\n        }\n\n        let is_stream_mode = self.is_stream_mode();\n        let book_snapshot_output = self.config.book_snapshot_output.clone();\n        let extract_bbo_as_quotes = self.config.extract_bbo_as_quotes;\n\n        let http_client = TardisHttpClient::new(","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/tardis/src/data.rs#L493-L529","documentation":"The Tardis data client's connect() requires the config to specify what data to consume: historical replay `options` or realtime `stream_options`. If both lists are empty there is nothing to subscribe to, so the client refuses to connect rather than opening a useless websocket session.","triggerScenarios":"Creating a TardisDataClient (or factory) with a TardisDataClientConfig where both `options` and `stream_options` are empty/default, then calling connect.","commonSituations":"Config built programmatically with all fields defaulted; options filtered out by conditional logic that produced an empty vec; user expected a default subscription set that doesn't exist.","solutions":["Populate `options` with TardisReplayOptions for historical data, e.g. TardisReplayOptions::new(exchange, \"trades\", symbols, None)","Populate `stream_options` with TardisStreamOptions for realtime feeds","Fix the config-building logic that produced an empty options list","Validate the config before constructing the client"],"exampleFix":"// before\nlet config = TardisDataClientConfig::default();  // both options empty\n// after\nlet config = TardisDataClientConfig {\n    options: vec![TardisReplayOptions::new(\"binance-futures\", \"trades\", Some(vec![\"btcusdt\".into()]), None)],\n    stream_options: vec![],\n    ..Default::default()\n};","handlingStrategy":"validation","validationCode":"fn validate_tardis_config(config: &TardisDataClientConfig) -> Result<(), String> {\n    if config.options.is_empty() && config.stream_options.is_empty() {\n        return Err(\"Provide at least one replay `options` or `stream_options` entry\".into());\n    }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":"match client.connect().await {\n    Ok(()) => {},\n    Err(e) if e.to_string().contains(\"Either replay `options`\") => {\n        eprintln!(\"Tardis config has no subscriptions; populate options/stream_options\");\n        return Err(e);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Never instantiate client configs with all-default (empty) subscription lists","Validate config invariants at load time, before engine startup","Log the number of configured subscriptions at startup"],"tags":["config","websocket","tardis","validation"],"backgroundTag":"missing-required-config-field","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"}