{"record":{"id":"c0fa52925b6a1c25","repo":"nautechsystems/nautilus_trader","slug":"invalid-derive-orderbook-channel-channel","errorCode":null,"errorMessage":"invalid Derive orderbook channel `{channel}`","messagePattern":"invalid Derive orderbook channel `(.+?)`","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/derive/src/data.rs","lineNumber":2295,"sourceCode":"    } else {\n        (Some(price), Some(size))\n    }\n}\n\nfn channel_is_active(\n    channels: &AtomicMap<InstrumentId, String>,\n    instrument_id: InstrumentId,\n    channel: &str,\n) -> bool {\n    channels\n        .get_cloned(&instrument_id)\n        .is_some_and(|active_channel| active_channel == channel)\n}\n\nfn orderbook_channel_parts(channel: &str) -> anyhow::Result<(String, String, String)> {\n    let rest = channel\n        .strip_prefix(\"orderbook.\")\n        .ok_or_else(|| anyhow::anyhow!(\"invalid Derive orderbook channel `{channel}`\"))?;\n    let mut parts = rest.rsplitn(3, '.');\n    let depth = parts\n        .next()\n        .filter(|value| !value.is_empty())\n        .ok_or_else(|| anyhow::anyhow!(\"invalid Derive orderbook channel `{channel}`\"))?;\n    let group = parts\n        .next()\n        .filter(|value| !value.is_empty())\n        .ok_or_else(|| anyhow::anyhow!(\"invalid Derive orderbook channel `{channel}`\"))?;\n    let instrument_name = parts\n        .next()\n        .filter(|value| !value.is_empty())\n        .ok_or_else(|| anyhow::anyhow!(\"invalid Derive orderbook channel `{channel}`\"))?;\n\n    Ok((\n        instrument_name.to_string(),\n        group.to_string(),\n        depth.to_string(),","sourceCodeStart":2277,"sourceCodeEnd":2313,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/derive/src/data.rs#L2277-L2313","documentation":"`orderbook_channel_parts` parses a Derive subscription channel name of the form `orderbook.<instrument>.<group>.<depth>`. This error fires when the string has no `orderbook.` prefix, so it cannot be an orderbook channel at all.","triggerScenarios":"Passing a channel string like `ticker.ETH-PERP` or a malformed/renamed channel to the orderbook channel parsing/unsubscription path.","commonSituations":"Hand-built subscription strings with a typo; a channel recorded under an older naming scheme; passing a ticker channel into an orderbook parser.","solutions":["Ensure the channel string starts with `orderbook.`.","Log/print the offending channel to see what was actually passed.","If handling multiple channel kinds, route ticker channels to `ticker_channel_parts` instead.","Check for typos or upstream renames of the channel format."],"exampleFix":"// before\norderbook_channel_parts(\"ticker.ETH-PERP.100ms\")?;\n\n// after\norderbook_channel_parts(\"orderbook.ETH-PERP.NONE.25\")?;","handlingStrategy":"validation","validationCode":"if !channel.starts_with(\"orderbook.\") {\n    // not an orderbook channel; route elsewhere or skip\n}","typeGuard":"fn is_orderbook_channel(channel: &str) -> bool {\n    channel.strip_prefix(\"orderbook.\")\n        .map(|r| r.split('.').filter(|s| !s.is_empty()).count() == 3)\n        .unwrap_or(false)\n}","tryCatchPattern":"match orderbook_channel_parts(channel) {\n    Ok((instrument, group, depth)) => { /* handle */ }\n    Err(e) => tracing::debug!(\"skipping non-orderbook channel: {e:#}\"),\n}","preventionTips":["Always build channels via the adapter's formatting helpers","Route by channel prefix before parsing","Validate channel strings right after subscription creation"],"tags":["derive","websocket","channel","parsing"],"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"}