{"record":{"id":"d5aa476e542c7824","repo":"nautechsystems/nautilus_trader","slug":"invalid-hyperliquid-symbol-format-symbol","errorCode":null,"errorMessage":"Invalid Hyperliquid symbol format: {symbol}","messagePattern":"Invalid Hyperliquid symbol format: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/hyperliquid/src/common/enums.rs","lineNumber":1046,"sourceCode":"    /// Extract product type from an instrument symbol.\n    ///\n    /// Accepts both Nautilus instrument symbols (`{BASE}-USD-PERP`,\n    /// `{BASE}-{QUOTE}-SPOT`, `{N}-{YES|NO}-OUTCOME`) and venue wire coin\n    /// names (`#<encoding>` / `+<encoding>` for HIP-4 outcomes). Callers in\n    /// the adapter pass both forms.\n    ///\n    /// # Errors\n    ///\n    /// Returns error if symbol doesn't match any expected format.\n    pub fn from_symbol(symbol: &str) -> anyhow::Result<Self> {\n        if symbol.ends_with(\"-PERP\") {\n            Ok(Self::Perp)\n        } else if symbol.ends_with(\"-SPOT\") {\n            Ok(Self::Spot)\n        } else if symbol.ends_with(OUTCOME_SYMBOL_SUFFIX) || is_outcome_wire_symbol(symbol) {\n            Ok(Self::Outcome)\n        } else {\n            anyhow::bail!(\"Invalid Hyperliquid symbol format: {symbol}\")\n        }\n    }\n}\n\n// Outcomes use the `#<encoding>` spot-coin form or the `+<encoding>` token\n// form, where the encoding is `10 * outcome + side` and must parse as `u32`.\nfn is_outcome_wire_symbol(symbol: &str) -> bool {\n    let Some(rest) = symbol\n        .strip_prefix('#')\n        .or_else(|| symbol.strip_prefix('+'))\n    else {\n        return false;\n    };\n    !rest.is_empty() && rest.parse::<u32>().is_ok()\n}\n\n/// Hyperliquid API environment.\n#[derive(","sourceCodeStart":1028,"sourceCodeEnd":1064,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/hyperliquid/src/common/enums.rs#L1028-L1064","documentation":"InstrumentId/symbol parsing for Hyperliquid classifies a symbol as perp, spot, or outcome by suffix (e.g. -SPOT or outcome encodings). A symbol matching none of the recognized forms bails with this error.","triggerScenarios":"Calling from_symbol with a symbol lacking a recognized suffix, e.g. plain \"BTC\" without the expected perp/spot/outcome form, or a malformed instrument ID string.","commonSituations":"Passing Binance-style symbols (BTCUSDT) into the Hyperliquid adapter; missing the @/spot or -SPOT suffix; using outcome tokens without the # or + prefix.","solutions":["Format the symbol per Hyperliquid conventions (perp form, spot form with -SPOT suffix, or #/+ outcome encoding).","Pre-validate the symbol suffix in your ingest/config layer before calling from_symbol.","Convert external symbols explicitly (e.g. BTCUSDT -> BTC or BTC-SPOT) rather than passing them through."],"exampleFix":"// before\nlet asset = HyperliquidAssetType::from_symbol(\"BTCUSDT\")?;\n// after\nlet asset = HyperliquidAssetType::from_symbol(\"BTC\")?; // perp\n// or HyperliquidAssetType::from_symbol(\"BTC-SPOT\")?;","handlingStrategy":"validation","validationCode":"fn looks_like_hl_symbol(s: &str) -> bool {\n    s.ends_with(\"-SPOT\") || s.starts_with('#') || s.starts_with('+') || !s.contains(\"USDT\")\n}","typeGuard":null,"tryCatchPattern":"match HyperliquidAssetType::from_symbol(sym) {\n    Ok(a) => use_asset(a),\n    Err(e) => { log::error!(\"{e}\"); /* convert symbol format and retry */ }\n}","preventionTips":["Normalize external symbols (e.g. BTCUSDT -> BTC / BTC-SPOT) before adapter calls.","Keep a symbol formatter per source exchange.","Reject unparseable symbols at ingest with a clear message."],"tags":["hyperliquid","symbol","parsing","rust"],"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"}