{"record":{"id":"c177a54b673c3ed6","repo":"nautechsystems/nautilus_trader","slug":"invalid-bybit-symbol-value-ref-expected-suffi","errorCode":null,"errorMessage":"invalid Bybit symbol '{value_ref}': expected suffix in {VALID_SUFFIXES:?}","messagePattern":"invalid Bybit symbol '(.+?)': expected suffix in (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/common/symbol.rs","lineNumber":52,"sourceCode":"pub struct BybitSymbol {\n    value: Ustr,\n}\n\nimpl BybitSymbol {\n    /// Creates a new [`BybitSymbol`] after validating the suffix and normalizing to upper case.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the value does not contain one of the recognized Bybit suffixes.\n    pub fn new<S: AsRef<str>>(value: S) -> anyhow::Result<Self> {\n        let value_ref = value.as_ref();\n        let needs_upper = value_ref.bytes().any(|b| b.is_ascii_lowercase());\n        let normalized: Cow<'_, str> = if needs_upper {\n            Cow::Owned(value_ref.to_ascii_uppercase())\n        } else {\n            Cow::Borrowed(value_ref)\n        };\n        anyhow::ensure!(\n            has_valid_suffix(normalized.as_ref()),\n            \"invalid Bybit symbol '{value_ref}': expected suffix in {VALID_SUFFIXES:?}\"\n        );\n        Ok(Self {\n            value: Ustr::from(normalized.as_ref()),\n        })\n    }\n\n    /// Returns the underlying symbol without the Bybit suffix.\n    #[must_use]\n    pub fn raw_symbol(&self) -> &str {\n        self.value\n            .rsplit_once('-')\n            .map_or(self.value.as_str(), |(prefix, _)| prefix)\n    }\n\n    /// Returns the product type identified by the suffix.\n    ///","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/common/symbol.rs#L34-L70","documentation":"The BybitSymbol newtype validates that raw input carries a valid Bybit product suffix (e.g. -SPOT, -LINEAR, -INVERSE). The input is uppercased, and if after normalization it still has no recognized suffix, construction fails. This prevents malformed instrument IDs from entering the adapter.","triggerScenarios":"Creating BybitSymbol::new(\"BTCUSDT\") or any symbol without a supported suffix such as -SPOT / -LINEAR / -INVERSE.","commonSituations":"Reusing symbol strings from another exchange adapter (Binance, Bybit raw API) without adding the NautilusTrader product suffix; hardcoding venue-neutral symbols in config.","solutions":["Append the correct suffix: e.g. BTCUSDT-LINEAR, ETHUSDT-SPOT, BTCUSDT-INVERSE","Check VALID_SUFFIXES in crates/adapters/bybit/src/common/symbol.rs for the accepted set","Convert via the instrument definitions from the Bybit API rather than raw ticker strings"],"exampleFix":"// before\nlet sym = BybitSymbol::new(\"BTCUSDT\")?;\n// after\nlet sym = BybitSymbol::new(\"BTCUSDT-LINEAR\")?;","handlingStrategy":"validation","validationCode":"fn has_valid_suffix(s: &str) -> bool {\n    [\"-SPOT\", \"-LINEAR\", \"-INVERSE\"].iter().any(|sfx| s.ends_with(sfx))\n}\n// check before construction:\nassert!(has_valid_suffix(&raw.to_ascii_uppercase()), \"add a Bybit product suffix\");","typeGuard":null,"tryCatchPattern":"let symbol = BybitSymbol::new(raw)\n    .with_context(|| format!(\"{raw} needs a Bybit suffix like -SPOT/-LINEAR/-INVERSE\"))?;","preventionTips":["Never reuse raw exchange tickers as Nautilus instrument IDs","Derive symbols from downloaded instrument definitions","Keep a central mapping from venue ticker to suffixed instrument ID"],"tags":["bybit","symbol","validation"],"backgroundTag":"invalid-identifier-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}