nautechsystems/nautilus_trader · error
heartbeat_interval_secs must be greater than 0
Error message
heartbeat_interval_secs must be greater than 0
What it means
RedisMessageBus::new validates MessageBusConfig before constructing the bus. A heartbeat interval of Some(0) is rejected because a zero-second heartbeat period would spin the heartbeat task in a tight loop, so the constructor fails fast with this error instead.
Source
Thrown at crates/infrastructure/src/redis/msgbus.rs:285
}
}
impl RedisMessageBusBacking {
/// Creates a new [`RedisMessageBusBacking`] instance for the given `trader_id`, `instance_id`, and `config`.
///
/// # Errors
///
/// Returns an error if the heartbeat interval is configured as zero seconds.
pub fn new(
trader_id: TraderId,
instance_id: UUID4,
config: MessageBusConfig,
backing: RedisMessageBusConfig,
) -> anyhow::Result<Self> {
install_cryptographic_provider();
if config.heartbeat_interval_secs == Some(0) {
anyhow::bail!("heartbeat_interval_secs must be greater than 0");
}
let external_streams = config.external_streams.clone().unwrap_or_default();
let heartbeat_interval_secs = config.heartbeat_interval_secs;
let publish = backing.clone();
let (pub_tx, pub_rx) = tokio::sync::mpsc::unbounded_channel::<BusMessage>();
// Create publish task (start the runtime here for now)
let pub_handle = Some(get_runtime().spawn(async move {
if let Err(e) = publish_messages(pub_rx, trader_id, instance_id, config, publish).await
{
log_task_error(MSGBUS_PUBLISH, &e);
}
}));
// Conditionally create stream task and channel if external streams configured
let stream_signal = Arc::new(AtomicBool::new(false));View on GitHub (pinned to 18893faf8b)
Solutions
- Set heartbeat_interval_secs to None if you want the heartbeat disabled
- Set a positive value, e.g. Some(30) for a 30-second heartbeat
- Clamp or validate the value where the config is loaded (env var / config file parsing) before constructing the bus
- Check the expression producing the interval — a zero-derived value usually signals an unset input
Example fix
// before
let config = MessageBusConfig { heartbeat_interval_secs: Some(0), .. };
// after
let config = MessageBusConfig { heartbeat_interval_secs: None, .. }; // or Some(30) Defensive patterns
Strategy: validation
Validate before calling
assert!(config.heartbeat_interval_secs.map_or(true, |s| s > 0), "heartbeat_interval_secs must be > 0 or None");
Try / catch
let bus = RedisMessageBus::new(config, backing)
.map_err(|e| if e.to_string().contains("heartbeat_interval_secs") { ConfigError::BadHeartbeat } else { e })?; Prevention
- Use None (not Some(0)) to disable the heartbeat
- Validate config at load time, before constructing the bus
- Derive intervals with saturating/max bounds, e.g. secs.max(1)
When it happens
Trigger: Constructing the message bus with MessageBusConfig { heartbeat_interval_secs: Some(0), .. } — passing zero explicitly rather than None (disabled) or a positive number.
Common situations: Copy-pasting a config template and setting 0 to 'disable' the heartbeat; computing the interval from an expression that evaluates to 0 (e.g. seconds parsed from an empty/zero env var).
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 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/87e63e23d6ace7ce.
Report an issue: GitHub.