nautechsystems/nautilus_trader · error
Invalid kline topic format: expected '{kline}.{{interval}}.{
Error message
Invalid kline topic format: expected '{kline}.{{interval}}.{{symbol}}', was '{topic}' What it means
`parse_kline_topic` expects a Bybit topic of exactly three dot-separated segments starting with `kline` (`kline.{interval}.{symbol}`). Any other segment count or prefix produces this error naming the expected shape and the actual topic.
Source
Thrown at crates/adapters/bybit/src/websocket/parse.rs:200
let parts: Vec<&str> = topic.split('.').collect();
if parts.is_empty() {
anyhow::bail!("Invalid topic format: empty topic");
}
Ok(parts)
}
/// Parses a Bybit kline topic into (interval, symbol).
///
/// Topic format: "kline.{interval}.{symbol}" (e.g., "kline.5.BTCUSDT")
///
/// # Errors
///
/// Returns an error if the topic format is invalid.
pub fn parse_kline_topic(topic: &str) -> anyhow::Result<(&str, &str)> {
let kline = BybitWsPublicChannel::Kline.as_ref();
let parts = parse_topic(topic)?;
if parts.len() != 3 || parts[0] != kline {
anyhow::bail!(
"Invalid kline topic format: expected '{kline}.{{interval}}.{{symbol}}', was '{topic}'"
);
}
Ok((parts[1], parts[2]))
}
/// Parses a WebSocket trade frame into a [`TradeTick`].
pub fn parse_ws_trade_tick(
trade: &BybitWsTrade,
instrument: &InstrumentAny,
ts_init: UnixNanos,
) -> anyhow::Result<TradeTick> {
let price = parse_price_with_precision(&trade.p, instrument.price_precision(), "trade.p")?;
let size = parse_quantity_with_precision(&trade.v, instrument.size_precision(), "trade.v")?;
let aggressor: AggressorSide = trade.taker_side.into();
let trade_id = TradeId::new_checked(trade.i.as_str())
.context("invalid trade identifier in Bybit trade message")?;
let ts_event = parse_millis_i64(trade.t, "trade.T")?;View on GitHub (pinned to 18893faf8b)
Solutions
- Dispatch messages by topic prefix before calling `parse_kline_topic` (e.g. only topics starting with `kline.`).
- Verify the subscription topic matches Bybit v5 public kline format: `kline.{interval}.{symbol}`.
- Check for Bybit API version changes if topic formats shifted after an exchange update.
Example fix
// before: parse every message as kline
let (interval, symbol) = parse_kline_topic(&topic)?;
// after: route by channel first
if topic.starts_with(BybitWsPublicChannel::Kline.as_ref()) {
let (interval, symbol) = parse_kline_topic(&topic)?;
} Defensive patterns
Strategy: type-guard
Validate before calling
fn is_kline_topic(topic: &str) -> bool {
let parts: Vec<&str> = topic.split('.').collect();
parts.len() == 3 && parts[0] == "kline"
} Type guard
fn as_kline_topic(topic: &str) -> Option<(&str, &str, &str)> {
let parts: Vec<&str> = topic.split('.').collect();
match parts.as_slice() {
["kline", interval, symbol] if !interval.is_empty() && !symbol.is_empty() => {
Some(("kline", interval, symbol))
}
_ => None,
}
} Try / catch
if is_kline_topic(&topic) {
let (interval, symbol) = parse_kline_topic(&topic)?;
} else {
tracing::debug!("non-kline topic ignored: {topic}");
} Prevention
- Route messages by channel prefix (kline/orderbook/publicTrade) before parsing
- Verify subscription strings match Bybit v5 `kline.{interval}.{symbol}`
- Re-check topic formats after Bybit API version upgrades
When it happens
Trigger: `handle_ws_message` receives a public WS message whose topic is not a kline topic (e.g. `orderbook.1.BTCUSDT`, `publicTrade.BTCUSDT`, or `kline.1.BTCUSDT.extra`) and `parse_kline_topic` is called on it.
Common situations: Subscribing to multiple public channels but routing every message through the kline parser; Bybit renaming/adding channel topics in a new API version; typos in subscription topic strings.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- errors.join("; ")
- Bybit data shutdown failed: {}
- Mark prices not available for Spot instruments
- Index prices not available for Spot instruments
- Bybit does not support kline/bar data for options
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c246096ada405b65.
Report an issue: GitHub.