nautechsystems/nautilus_trader · error · anyhow::Error

invalid UUID broker client order ID payload length

Error message

invalid UUID broker client order ID payload length

What it means

Decoding a broker-prefixed client order ID whose signal byte marks the UUID-format payload: the base62 characters after the signal must be exactly UUID_B62_LEN long. A different length means the value cannot be decoded back into the original UUID-based ClientOrderId.

Source

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

    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(),
                "missing raw broker client order ID payload"
            );
            Ok(raw.to_string())
        }
        _ => anyhow::bail!(
            "unknown broker client order ID signal byte '{}'",
            signal as char
        ),

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Align encoder and decoder versions - orders written by an older adapter must be read by that version or treated as opaque
  2. Choose a distinctive broker_id to avoid collisions with exchange- or user-generated IDs
  3. Treat un-decodable IDs as raw values instead of failing the whole order update path

Example fix

// before
let cid = decode_broker_id_checked(encoded, broker_id)?;

// after: fall back to treating the value as an opaque ID
let cid = decode_broker_id_checked(encoded, broker_id)
    .map(ClientOrderId::new)
    .unwrap_or_else(|_| ClientOrderId::new(encoded.to_string()));
Defensive patterns

Strategy: type-guard

Validate before calling

fn is_valid_uuid_format(id: &str, prefix: &str, uuid_len: usize) -> bool {
    match id.strip_prefix(prefix) {
        Some(p) if !p.is_empty() => p[1..].len() == uuid_len,
        _ => true,
    }
}

Type guard

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

Try / catch

match decode_broker_id_checked(encoded, broker_id) {
    Ok(decoded) => ClientOrderId::new_checked(decoded)?,
    Err(e) => {
        log::warn!("UUID-format decode failed for '{encoded}': {e}");
        ClientOrderId::new(encoded) // opaque fallback
    }
}

Prevention

When it happens

Trigger: A clientOrderId starting with broker prefix + UUID signal byte but whose payload length is not the fixed UUID base62 length - truncated IDs, foreign IDs colliding with the prefix, or an encoder/decoder version mismatch.

Common situations: Upgrading adapter versions that changed UUID packing; replaying orders created by an older build; user-defined IDs that begin with the configured prefix followed by a UUID signal character.

Related errors


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