nautechsystems/nautilus_trader · error
Wrong template ID: expected {execution_report_event_codec::S
Error message
Wrong template ID: expected {execution_report_event_codec::SBE_TEMPLATE_ID}, received {template_id} What it means
decode_execution_report validates the 8-byte SBE message header of a Binance Spot user-data binary frame before decoding. This error fires when the header's template ID is not the ExecutionReportEvent template (603), meaning the payload is a different SBE message type routed to the wrong decoder. The library bails early instead of misinterpreting bytes of another template as an execution report.
Source
Thrown at crates/adapters/binance/src/spot/websocket/trading/decode_sbe.rs:77
///
/// Returns error if the buffer is too short, the template ID is wrong,
/// the schema ID does not match, or variable-length data is malformed.
pub fn decode_execution_report(data: &[u8]) -> anyhow::Result<BinanceSpotExecutionReport> {
if data.len() < HEADER_LEN {
anyhow::bail!(
"Buffer too short for SBE header: expected {HEADER_LEN}, was {}",
data.len()
);
}
let buf = ReadBuf::new(data);
let block_length = buf.get_u16_at(0);
let template_id = buf.get_u16_at(2);
let schema_id = buf.get_u16_at(4);
let version = buf.get_u16_at(6);
if template_id != execution_report_event_codec::SBE_TEMPLATE_ID {
anyhow::bail!(
"Wrong template ID: expected {}, received {template_id}",
execution_report_event_codec::SBE_TEMPLATE_ID
);
}
if schema_id != crate::spot::sbe::spot::SBE_SCHEMA_ID {
anyhow::bail!(
"Wrong schema ID: expected {}, received {schema_id}",
crate::spot::sbe::spot::SBE_SCHEMA_ID
);
}
let min_block_len = execution_report_min_block_length(version);
if usize::from(block_length) < min_block_len {
anyhow::bail!(
"SBE execution report block length too short: expected at least {min_block_len}, was {block_length}"
);
}View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the frame actually came from the executionReport user-data event before calling this decoder
- Parse the SBE header's template ID first and dispatch to the matching decoder (601→balance update, 603→execution report, 607→account position)
- Regenerate/update the codecs if Binance bumped the template ID in a schema revision
- Fix test fixtures to use a buffer encoded with the execution_report_event_codec
Example fix
// before
let report = decode_execution_report(raw_frame).unwrap();
// after
let template_id = u16::from_be_bytes([raw_frame[2], raw_frame[3]]);
let report = match template_id {
execution_report_event_codec::SBE_TEMPLATE_ID => decode_execution_report(raw_frame)?,
_ => return Err(anyhow::format_err!("unexpected template {template_id}")),
}; Defensive patterns
Strategy: validation
Validate before calling
pub fn is_execution_report_frame(data: &[u8]) -> bool {
data.len() >= 8
&& u16::from_be_bytes([data[2], data[3]]) == execution_report_event_codec::SBE_TEMPLATE_ID
} Type guard
fn as_execution_report(data: &[u8]) -> Option<&[u8]> {
(data.len() >= 8
&& u16::from_be_bytes([data[2], data[3]]) == execution_report_event_codec::SBE_TEMPLATE_ID)
.then_some(data)
} Try / catch
match decode_execution_report(&frame) {
Ok(report) => handle(report),
Err(e) if e.to_string().contains("Wrong template ID") => route_to_other_decoder(&frame),
Err(e) => log::warn!("SBE decode failed: {e}"),
} Prevention
- Dispatch SBE frames on the parsed header template ID before choosing a decoder
- Keep a single header-parsing helper instead of ad-hoc byte slicing
- Keep test fixtures per event type, encoded with the matching codec
- Regenerate codecs whenever Binance bumps the SBE schema
When it happens
Trigger: Calling decode_execution_report with a binary payload whose SBE header (bytes 2-3) carries a template ID other than 603 — e.g. a BalanceUpdateEvent (601) or OutboundAccountPositionEvent (607) frame, an out-of-order/duplicated stream event, or a hand-built test buffer with the wrong template.
Common situations: Routing frames by stream name instead of parsing the template ID before dispatch; Binance changing or the user mis-mapping user-data event types; writing unit tests that reuse a captured buffer from a different event type.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Buffer too short for SBE header: expected {HEADER_LEN}, was
- Wrong template ID: expected {outbound_account_position_event
- Failed to advance balances group: {e:?}
- missing broker client order ID signal
- unknown broker client order ID signal byte '{}'
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/168eb7482d97fe56.
Report an issue: GitHub.