nautechsystems/nautilus_trader · error
Either replay `options` or `stream_options` must be provided
Error message
Either replay `options` or `stream_options` must be provided
What it means
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.
Source
Thrown at crates/adapters/tardis/src/data.rs:511
fn unsubscribe_mark_prices(&mut self, _cmd: &UnsubscribeMarkPrices) -> anyhow::Result<()> {
Ok(())
}
fn unsubscribe_index_prices(&mut self, _cmd: &UnsubscribeIndexPrices) -> anyhow::Result<()> {
Ok(())
}
fn unsubscribe_funding_rates(&mut self, _cmd: &UnsubscribeFundingRates) -> anyhow::Result<()> {
Ok(())
}
async fn connect(&mut self) -> anyhow::Result<()> {
if self.is_connected() && self.tasks.is_open() {
return Ok(());
}
if self.config.options.is_empty() && self.config.stream_options.is_empty() {
anyhow::bail!("Either replay `options` or `stream_options` must be provided");
}
if !self.tasks.is_open() {
self.tasks
.finish_shutdown(Duration::from_secs(1), Duration::from_secs(2))
.await
.map_err(|e| anyhow::anyhow!("Failed to terminate Tardis tasks: {e}"))?;
self.tasks
.start_generation()
.map_err(|e| anyhow::anyhow!("Failed to start Tardis task generation: {e}"))?;
self.cancellation_token = self.tasks.cancellation_token();
}
let is_stream_mode = self.is_stream_mode();
let book_snapshot_output = self.config.book_snapshot_output.clone();
let extract_bbo_as_quotes = self.config.extract_bbo_as_quotes;
let http_client = TardisHttpClient::new(View on GitHub (pinned to 18893faf8b)
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
Example fix
// before
let config = TardisDataClientConfig::default(); // both options empty
// after
let config = TardisDataClientConfig {
options: vec![TardisReplayOptions::new("binance-futures", "trades", Some(vec!["btcusdt".into()]), None)],
stream_options: vec![],
..Default::default()
}; Defensive patterns
Strategy: validation
Validate before calling
fn validate_tardis_config(config: &TardisDataClientConfig) -> Result<(), String> {
if config.options.is_empty() && config.stream_options.is_empty() {
return Err("Provide at least one replay `options` or `stream_options` entry".into());
}
Ok(())
} Try / catch
match client.connect().await {
Ok(()) => {},
Err(e) if e.to_string().contains("Either replay `options`") => {
eprintln!("Tardis config has no subscriptions; populate options/stream_options");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- 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
When it happens
Trigger: Creating a TardisDataClient (or factory) with a TardisDataClientConfig where both `options` and `stream_options` are empty/default, then calling connect.
Common situations: 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.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- request_rate_per_second must be greater than zero
- order_request_rate_per_second must be greater than zero
- heartbeat_secs must be positive when set
- heartbeat_timeout_secs must cover at least two server heartb
- `router_addresses` must contain at least one router address
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1662dd40d0bf59f0.
Report an issue: GitHub.