nautechsystems/nautilus_trader · error

Invalid `external_order_claims` instrument ID {claim}: {e}

Error message

Invalid `external_order_claims` instrument ID {claim}: {e}

What it means

An element of external_order_claims was a string but could not be parsed as an InstrumentId (expected 'SYMBOL.VENUE' format).

Source

Thrown at crates/live/src/python/node.rs:1849

        return Ok(None);
    };

    if claims.is_none() {
        return Ok(None);
    }

    if let Ok(claims) = claims.extract::<Vec<InstrumentId>>() {
        return Ok(Some(claims));
    }

    let claim_strings = claims
        .extract::<Vec<String>>()
        .map_err(|e| anyhow::anyhow!("Invalid `external_order_claims` type: {e}"))?;
    let claims = claim_strings
        .into_iter()
        .map(|claim| {
            InstrumentId::from_str(&claim).map_err(|e| {
                anyhow::anyhow!("Invalid `external_order_claims` instrument ID {claim}: {e}")
            })
        })
        .collect::<anyhow::Result<Vec<_>>>()?;

    Ok(Some(claims))
}

#[cfg(feature = "examples")]
type BuiltinActorRegister = for<'py> fn(&mut LiveNode, &Bound<'py, PyAny>) -> PyResult<()>;

#[cfg(feature = "examples")]
type BuiltinStrategyRegister = for<'py> fn(&mut LiveNode, &Bound<'py, PyAny>) -> PyResult<()>;

#[cfg(feature = "examples")]
fn builtin_actor_register(type_name: &str) -> Option<BuiltinActorRegister> {
    match type_name {
        "BookImbalanceActor" => Some(register_book_imbalance_actor),
        "DataTester" => Some(register_data_tester),

View on GitHub (pinned to d1527c24af)

Solutions

  1. Use the fully qualified format SYMBOL.VENUE, e.g. "BTCUSDT.BINANCE"
  2. Check for stray whitespace/typos in the venue part
  3. Confirm the instrument ID matches what the adapter publishes (same casing/format)

Example fix

# before
external_order_claims = ["BTCUSDT-PERP"]

# after
external_order_claims = ["BTCUSDT-PERP.BINANCE"]
Defensive patterns

Strategy: validation

Validate before calling

# Python
from nautilus_trader.model.identifiers import InstrumentId
InstrumentId.from_str(claim)  # raises early with clear error if malformed

Type guard

# Python
def is_valid_instrument_id(s: str) -> bool:
    try:
        InstrumentId.from_str(s)
        return True
    except Exception:
        return False

Try / catch

try:
    node = build_node(config)
except Exception as e:
    if "instrument ID" in str(e):
        # fix claim strings to SYMBOL.VENUE and retry

Prevention

When it happens

Trigger: Passing strings like "btcusdt" without the venue qualifier, wrong separator, whitespace, or an unregistered venue string.

Common situations: Copy-pasting a raw ticker symbol instead of the fully qualified Nautilus instrument ID.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@d1527c24af (2026-08-27). Data as JSON: /api/errors/4a4cb0a534d23f15. Report an issue: GitHub.