nautechsystems/nautilus_trader · error · anyhow::Error

invalid O-format broker client order ID payload length

Error message

invalid O-format broker client order ID payload length

What it means

Decoding a broker-prefixed client order ID whose signal byte marks the packed 'O-format' payload: the base62 characters after the signal must be exactly O_FORMAT_B62_LEN long. The observed payload length differs, so the packed representation cannot be unpacked into the original ID.

Source

Thrown at crates/adapters/binance/src/common/encoder.rs:240

) -> anyhow::Result<ClientOrderId> {
    let decoded = decode_broker_id_checked(encoded, broker_id)?;
    ClientOrderId::new_checked(decoded)
        .with_context(|| format!("invalid Binance client order ID '{encoded}'"))
}

fn decode_broker_id_checked(encoded: &str, broker_id: &str) -> anyhow::Result<String> {
    let prefix = broker_prefix(broker_id);
    let Some(payload) = encoded.strip_prefix(&prefix) else {
        return Ok(encoded.to_string());
    };

    let Some((&signal, data)) = payload.as_bytes().split_first() else {
        anyhow::bail!("missing broker client order ID signal");
    };

    match signal {
        SIGNAL_O_HYPHENS | SIGNAL_O_NO_HYPHENS => {
            anyhow::ensure!(
                data.len() == O_FORMAT_B62_LEN,
                "invalid O-format broker client order ID payload length"
            );
            let packed = decode_base62(data).context("invalid O-format broker client order ID")?;
            Ok(unpack_o_format(packed, signal == SIGNAL_O_HYPHENS))
        }
        SIGNAL_UUID_HYPHENS | SIGNAL_UUID_NO_HYPHENS => {
            anyhow::ensure!(
                data.len() == UUID_B62_LEN,
                "invalid UUID broker client order ID payload length"
            );
            let value = decode_base62(data).context("invalid UUID broker client order ID")?;
            Ok(format_uuid(value, signal == SIGNAL_UUID_HYPHENS))
        }
        SIGNAL_RAW => {
            let raw = std::str::from_utf8(data).context("invalid raw broker client order ID")?;
            anyhow::ensure!(
                !raw.is_empty(),

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Ensure the same adapter version encoded and decodes the ID (format lengths changed across versions - align writer and reader)
  2. Use a longer, distinctive broker_id so foreign IDs cannot collide with prefix+signal
  3. Verify the ID was not truncated in transit or storage (Binance caps clientOrderId length)

Example fix

// before: mixing an old capture with a new decoder
let cid = decode_broker_id_checked(&stored_id, "BNB")?;

// after: re-encode with the current adapter and re-store
let cid = ClientOrderId::new(stored_id.clone()); // accept as opaque raw value
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_valid_o_format(id: &str, prefix: &str, o_len: usize) -> bool {
    match id.strip_prefix(prefix) {
        Some(p) if !p.is_empty() => &p[1..].len() == o_len,
        _ => true, // not ours / signal-less: pass through
    }
}

Type guard

fn looks_like_adapter_o_id(id: &str, prefix: &str, o_b62_len: usize) -> bool {
    id.strip_prefix(prefix)
        .is_some_and(|p| p.len() == 1 + o_b62_len)
}

Try / catch

if let Err(e) = decode_broker_id_checked(encoded, broker_id) {
    log::warn!("unparseable broker ID '{encoded}' (possible version mismatch): {e}");
    // fall back to opaque handling, keep order flow alive
}

Prevention

When it happens

Trigger: An ID that starts with the broker prefix and carries an O-format signal byte but whose payload was truncated or extended - e.g. a foreign ID colliding with the prefix+signal, storage truncation at Binance's clientOrderId limit, or IDs produced by a different encoder version with another format length.

Common situations: Mixed adapter versions writing and reading the same orders; externally generated order IDs that coincidentally begin with prefix+signal; corrupted captured data being replayed.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/d986611c1464fd9e. Report an issue: GitHub.