nautechsystems/nautilus_trader · error

Buffer too short for {field}: expected {expected_len}, was {

Error message

Buffer too short for {field}: expected {expected_len}, was {}

What it means

Each variable-length field in the ExecutionReportEvent is a 1-byte length followed by that many bytes. This error fires when a field's length byte was read but the buffer ends before the field's full data, i.e. data.len() < field_offset + 1 + length. The decoder bails rather than decoding a short string.

Source

Thrown at crates/adapters/binance/src/spot/websocket/trading/decode_sbe.rs:116

    if data.len() < min_len {
        anyhow::bail!(
            "Buffer too short for fixed block: expected {min_len}, was {}",
            data.len()
        );
    }

    let mut field_offset = min_len;
    for field in EXECUTION_REPORT_VAR_DATA_FIELDS {
        let Some(length) = data.get(field_offset) else {
            anyhow::bail!(
                "Buffer too short for {field} length: expected {}, was {}",
                field_offset + 1,
                data.len()
            );
        };
        let expected_len = field_offset + 1 + usize::from(*length);
        if data.len() < expected_len {
            anyhow::bail!(
                "Buffer too short for {field}: expected {expected_len}, was {}",
                data.len()
            );
        }
        field_offset = expected_len;
    }

    let mut dec = execution_report_event_codec::ExecutionReportEventDecoder::default().wrap(
        buf,
        HEADER_LEN,
        block_length,
        version,
    );

    let price_exp = dec.price_exponent();
    let qty_exp = dec.qty_exponent();
    let commission_exp = dec.commission_exponent();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the entire frame is delivered before decoding (complete WebSocket reassembly)
  2. Re-encode the message with execution_report_event_codec to regenerate a consistent buffer
  3. Validate frame completeness (checksum or length accounting) upstream
  4. Fix capture/replay tooling that clips the final bytes

Example fix

// before
let frame = &captured[..captured.len() - 2]; // accidental clip
let report = decode_execution_report(frame)?;
// after
let report = decode_execution_report(captured)?; // full frame preserved
Defensive patterns

Strategy: validation

Validate before calling

pub fn var_fields_intact(data: &[u8]) -> bool {
    if data.len() < 8 { return false; }
    let block_length = u16::from_be_bytes([data[0], data[1]]) as usize;
    let mut off = 8 + block_length;
    for _ in 0..6 {
        let Some(&len) = data.get(off) else { return false };
        off += 1 + len as usize;
    }
    off <= data.len()
}

Type guard

fn intact_var_section<'a>(data: &'a [u8]) -> Option<&'a [u8]> {
    var_fields_intact(data).then_some(data)
}

Try / catch

match decode_execution_report(&frame) {
    Ok(r) => handle(r),
    Err(e) if e.to_string().contains("Buffer too short") => {
        log::debug!("dropping truncated frame ({} bytes)", frame.len());
    }
    Err(e) => log::warn!("SBE decode failed: {e}"),
}

Prevention

When it happens

Trigger: Calling decode_execution_report with a frame whose trailing variable-length section is cut mid-field — e.g. a symbol advertised as 6 bytes but only 3 present; truncated network message or truncated capture.

Common situations: Network/truncation issues splitting SBE frames; binary fixtures clipped at a byte boundary; corruption when persisting or replaying captured messages.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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