nautechsystems/nautilus_trader · error · anyhow::Error

invalid Bybit symbol '{value_ref}': expected suffix in {VALI

Error message

invalid Bybit symbol '{value_ref}': expected suffix in {VALID_SUFFIXES:?}

What it means

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.

Source

Thrown at crates/adapters/bybit/src/common/symbol.rs:52

pub struct BybitSymbol {
    value: Ustr,
}

impl BybitSymbol {
    /// Creates a new [`BybitSymbol`] after validating the suffix and normalizing to upper case.
    ///
    /// # Errors
    ///
    /// Returns an error if the value does not contain one of the recognized Bybit suffixes.
    pub fn new<S: AsRef<str>>(value: S) -> anyhow::Result<Self> {
        let value_ref = value.as_ref();
        let needs_upper = value_ref.bytes().any(|b| b.is_ascii_lowercase());
        let normalized: Cow<'_, str> = if needs_upper {
            Cow::Owned(value_ref.to_ascii_uppercase())
        } else {
            Cow::Borrowed(value_ref)
        };
        anyhow::ensure!(
            has_valid_suffix(normalized.as_ref()),
            "invalid Bybit symbol '{value_ref}': expected suffix in {VALID_SUFFIXES:?}"
        );
        Ok(Self {
            value: Ustr::from(normalized.as_ref()),
        })
    }

    /// Returns the underlying symbol without the Bybit suffix.
    #[must_use]
    pub fn raw_symbol(&self) -> &str {
        self.value
            .rsplit_once('-')
            .map_or(self.value.as_str(), |(prefix, _)| prefix)
    }

    /// Returns the product type identified by the suffix.
    ///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Append the correct suffix: e.g. BTCUSDT-LINEAR, ETHUSDT-SPOT, BTCUSDT-INVERSE
  2. Check VALID_SUFFIXES in crates/adapters/bybit/src/common/symbol.rs for the accepted set
  3. Convert via the instrument definitions from the Bybit API rather than raw ticker strings

Example fix

// before
let sym = BybitSymbol::new("BTCUSDT")?;
// after
let sym = BybitSymbol::new("BTCUSDT-LINEAR")?;
Defensive patterns

Strategy: validation

Validate before calling

fn has_valid_suffix(s: &str) -> bool {
    ["-SPOT", "-LINEAR", "-INVERSE"].iter().any(|sfx| s.ends_with(sfx))
}
// check before construction:
assert!(has_valid_suffix(&raw.to_ascii_uppercase()), "add a Bybit product suffix");

Try / catch

let symbol = BybitSymbol::new(raw)
    .with_context(|| format!("{raw} needs a Bybit suffix like -SPOT/-LINEAR/-INVERSE"))?;

Prevention

When it happens

Trigger: Creating BybitSymbol::new("BTCUSDT") or any symbol without a supported suffix such as -SPOT / -LINEAR / -INVERSE.

Common situations: Reusing symbol strings from another exchange adapter (Binance, Bybit raw API) without adding the NautilusTrader product suffix; hardcoding venue-neutral symbols in config.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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