nautechsystems/nautilus_trader · error
Missing topic at index {index}
Error message
Missing topic at index {index} What it means
This error means log.topics has no entry at the requested index when extract_topic_bytes is called. Ethereum topics are indexed 0..3 (topic0 = event signature); requesting an index beyond the topic count indicates a wrong event layout assumption or a log from a different event. The topic's hex is then hex-decoded (which can itself fail with a decode error).
Source
Thrown at crates/adapters/blockchain/src/rpc/log.rs:128
anyhow::ensure!(
bytes.len() == Address::len_bytes(),
"Invalid contract address length: expected {} bytes, was {}",
Address::len_bytes(),
bytes.len()
);
Ok(Address::from_slice(&bytes))
}
/// Extract topic bytes at index.
///
/// # Errors
///
/// Returns an error if the topic at the specified index is missing.
pub fn extract_topic_bytes(log: &RpcLog, index: usize) -> anyhow::Result<Vec<u8>> {
let hex = log
.topics
.get(index)
.ok_or_else(|| anyhow::anyhow!("Missing topic at index {index}"))?;
decode_hex(hex)
}
/// Extract address from topic at index.
///
/// In Ethereum event logs, indexed address parameters are stored as 32-byte
/// values with the 20-byte address right-aligned (padded with zeros on the left).
///
/// # Errors
///
/// Returns an error if the topic is missing or the address extraction fails.
pub fn extract_address_from_topic(
log: &RpcLog,
index: usize,
description: &str,
) -> anyhow::Result<Address> {
let bytes = extract_topic_bytes(log, index)
.map_err(|_| anyhow::anyhow!("Missing {description} address in topic{index}"))?;View on GitHub (pinned to 18893faf8b)
Solutions
- Check log.topics.len() before accessing higher indices.
- Verify topic0 against the expected event signature hash before parsing topics.
- Handle the specific index defensively: treat missing topics as an incompatible event and skip.
- Update your ABI/event layout assumptions if the contract changed.
Example fix
// before
let topic = extract_topic_bytes(&log, 1)?;
// after
if log.topics.len() <= 1 {
return Err(anyhow::anyhow!("event has no indexed param 1"));
}
let topic = extract_topic_bytes(&log, 1)?; Defensive patterns
Strategy: validation
Validate before calling
fn has_topic(log: &RpcLog, index: usize) -> bool { log.topics.len() > index } Type guard
fn topic_at<'a>(log: &'a RpcLog, i: usize) -> Option<&'a str> { log.topics.get(i).map(|s| s.as_str()) } Try / catch
match extract_topic_bytes(&log, 1) {
Ok(t) => t,
Err(_) => { skip_incompatible_event(&log); Vec::new() }
} Prevention
- Verify topic0 matches the expected event signature before parsing.
- Check topics length before accessing higher indices.
- Remember anonymous events and non-indexed params reduce topic count.
- Update decoder layouts when contract ABIs change.
When it happens
Trigger: Calling extract_topic_bytes(log, 1..) on an anonymous event or an event with fewer indexed parameters than assumed; calling it on a log from a different event type than expected.
Common situations: Contract upgrades changing indexed parameters, parsing logs for one event with a decoder built for another, or events with zero indexed args (topics containing only topic0).
Related errors
- Missing {description} address in topic{index}
- Topic must be at least 32 bytes, was {}
- Canonical nonce advanced without an authenticated signer tra
- Receipt verification is locally invalid for transaction {tx_
- Canonical nonce {} is outside the owned reconciliation range
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d80672b47fd83ddd.
Report an issue: GitHub.