nautechsystems/nautilus_trader · error · anyhow::Error

Not a subscription channel: {kind}

Error message

Not a subscription channel: {kind}

What it means

The Hyperliquid WebSocket adapter validates that the requested channel kind can actually be subscribed to. Response-only channels — SubscriptionResponse, User, Post, Pong, and Error — are message categories the server sends, not topics a client can subscribe to, so passing any of them to the subscription-topic conversion bails with this error. It is a fail-fast guard preventing an invalid subscription request from being sent.

Source

Thrown at crates/adapters/hyperliquid/src/websocket/client.rs:2409

            })
        }
        HyperliquidWsChannel::UserTwapSliceFills => Ok(SubscriptionRequest::UserTwapSliceFills {
            user: rest.context("Missing user")?.to_string(),
        }),
        HyperliquidWsChannel::UserTwapHistory => Ok(SubscriptionRequest::UserTwapHistory {
            user: rest.context("Missing user")?.to_string(),
        }),
        HyperliquidWsChannel::Bbo => Ok(SubscriptionRequest::Bbo {
            coin: Ustr::from(rest.context("Missing coin")?),
        }),

        // Response-only channels are not valid subscription topics
        HyperliquidWsChannel::SubscriptionResponse
        | HyperliquidWsChannel::User
        | HyperliquidWsChannel::Post
        | HyperliquidWsChannel::Pong
        | HyperliquidWsChannel::Error => {
            anyhow::bail!("Not a subscription channel: {kind}")
        }
    }
}

#[cfg(test)]
mod tests {
    use nautilus_live::{SocketReconnectRegistry, SocketReconnectRequestOutcome};
    use nautilus_model::identifiers::ClientId;
    use nautilus_network::mode::ReconnectRequestOutcome;
    use rstest::rstest;
    use ustr::Ustr;

    use super::*;
    use crate::{
        common::{
            consts::{HYPERLIQUID_WS_POST_INFLIGHT_MAX, HYPERLIQUID_WS_SUBSCRIPTIONS_MAX},
            enums::HyperliquidBarInterval,
        },

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use a valid subscription channel (e.g. trades, l2Book, allMids, candle, userEvents) instead of the response-only variant.
  2. Add a whitelist/filter before subscribing that rejects SubscriptionResponse, User, Post, Pong, and Error.
  3. If the channel comes from user config, validate/parse it into a dedicated subscribable-channels enum at config-load time.

Example fix

// before
let channel: HyperliquidWsChannel = value.parse()?;
client.subscribe(channel, args).await?;
// after
let channel: HyperliquidWsChannel = value.parse()?;
if !matches!(channel,
    HyperliquidWsChannel::SubscriptionResponse
    | HyperliquidWsChannel::User
    | HyperliquidWsChannel::Post
    | HyperliquidWsChannel::Pong
    | HyperliquidWsChannel::Error)
{
    client.subscribe(channel, args).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

const SUBSCRIBABLE: &[HyperliquidWsChannel] = &[
    HyperliquidWsChannel::Trades,
    HyperliquidWsChannel::L2Book,
    HyperliquidWsChannel::AllMids,
    HyperliquidWsChannel::Candle,
];
fn is_subscribable(ch: &HyperliquidWsChannel) -> bool {
    SUBSCRIBABLE.contains(ch)
}

Type guard

fn is_response_only(ch: &HyperliquidWsChannel) -> bool {
    matches!(ch,
        HyperliquidWsChannel::SubscriptionResponse
        | HyperliquidWsChannel::User
        | HyperliquidWsChannel::Post
        | HyperliquidWsChannel::Pong
        | HyperliquidWsChannel::Error)
}

Prevention

When it happens

Trigger: Calling the subscribe API (or building a HyperliquidSubscription) with channel = SubscriptionResponse, User, Post, Pong, or Error. Typically happens when code maps a generic channel enum or a user-supplied string into HyperliquidWsChannel without filtering response-only variants.

Common situations: Constructing subscriptions from parsed config where the channel string resolves to a response-only variant; writing generic routing code that forwards every channel enum to subscribe; typos or misunderstanding of which Hyperliquid channels are subscribable vs. reply-only.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/ec37043199a32b61. Report an issue: GitHub.