{"record":{"id":"c246096ada405b65","repo":"nautechsystems/nautilus_trader","slug":"invalid-kline-topic-format-expected-kline-in","errorCode":null,"errorMessage":"Invalid kline topic format: expected '{kline}.{{interval}}.{{symbol}}', was '{topic}'","messagePattern":"Invalid kline topic format: expected '(.+?)\\.(.+?)\\}\\.(.+?)\\}', was '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/websocket/parse.rs","lineNumber":200,"sourceCode":"    let parts: Vec<&str> = topic.split('.').collect();\n    if parts.is_empty() {\n        anyhow::bail!(\"Invalid topic format: empty topic\");\n    }\n    Ok(parts)\n}\n\n/// Parses a Bybit kline topic into (interval, symbol).\n///\n/// Topic format: \"kline.{interval}.{symbol}\" (e.g., \"kline.5.BTCUSDT\")\n///\n/// # Errors\n///\n/// Returns an error if the topic format is invalid.\npub fn parse_kline_topic(topic: &str) -> anyhow::Result<(&str, &str)> {\n    let kline = BybitWsPublicChannel::Kline.as_ref();\n    let parts = parse_topic(topic)?;\n    if parts.len() != 3 || parts[0] != kline {\n        anyhow::bail!(\n            \"Invalid kline topic format: expected '{kline}.{{interval}}.{{symbol}}', was '{topic}'\"\n        );\n    }\n    Ok((parts[1], parts[2]))\n}\n\n/// Parses a WebSocket trade frame into a [`TradeTick`].\npub fn parse_ws_trade_tick(\n    trade: &BybitWsTrade,\n    instrument: &InstrumentAny,\n    ts_init: UnixNanos,\n) -> anyhow::Result<TradeTick> {\n    let price = parse_price_with_precision(&trade.p, instrument.price_precision(), \"trade.p\")?;\n    let size = parse_quantity_with_precision(&trade.v, instrument.size_precision(), \"trade.v\")?;\n    let aggressor: AggressorSide = trade.taker_side.into();\n    let trade_id = TradeId::new_checked(trade.i.as_str())\n        .context(\"invalid trade identifier in Bybit trade message\")?;\n    let ts_event = parse_millis_i64(trade.t, \"trade.T\")?;","sourceCodeStart":182,"sourceCodeEnd":218,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/websocket/parse.rs#L182-L218","documentation":"`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.","triggerScenarios":"`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.","commonSituations":"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.","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."],"exampleFix":"// before: parse every message as kline\nlet (interval, symbol) = parse_kline_topic(&topic)?;\n// after: route by channel first\nif topic.starts_with(BybitWsPublicChannel::Kline.as_ref()) {\n    let (interval, symbol) = parse_kline_topic(&topic)?;\n}","handlingStrategy":"type-guard","validationCode":"fn is_kline_topic(topic: &str) -> bool {\n    let parts: Vec<&str> = topic.split('.').collect();\n    parts.len() == 3 && parts[0] == \"kline\"\n}","typeGuard":"fn as_kline_topic(topic: &str) -> Option<(&str, &str, &str)> {\n    let parts: Vec<&str> = topic.split('.').collect();\n    match parts.as_slice() {\n        [\"kline\", interval, symbol] if !interval.is_empty() && !symbol.is_empty() => {\n            Some((\"kline\", interval, symbol))\n        }\n        _ => None,\n    }\n}","tryCatchPattern":"if is_kline_topic(&topic) {\n    let (interval, symbol) = parse_kline_topic(&topic)?;\n} else {\n    tracing::debug!(\"non-kline topic ignored: {topic}\");\n}","preventionTips":["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"],"tags":["bybit","websocket","kline","topic-format"],"backgroundTag":"invalid-argument-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}