nautechsystems/nautilus_trader · error
Missing tickLower in topic2 when parsing burn event
Error message
Missing tickLower in topic2 when parsing burn event
What it means
parse_burn_event_hypersync reads the int24 tickLower from topic2 of a Uniswap V3 Burn log. If the log has fewer than 3 topics (topic2 absent), the match falls to the None arm and bails with 'Missing tickLower in topic2 when parsing burn event'. The Burn event ABI requires (owner, tickLower, tickUpper) as indexed topics, so a missing topic2 means the log is not a well-formed Burn event.
Source
Thrown at crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/burn.rs:66
/// # Errors
///
/// Returns an error if the log parsing fails or if the event data is invalid.
///
/// # Panics
///
/// Panics if the contract address is not set in the log.
pub fn parse_burn_event_hypersync(dex: SharedDex, log: &HypersyncLog) -> anyhow::Result<BurnEvent> {
validate_event_signature_hash("Burn", BURN_EVENT_SIGNATURE_HASH, log)?;
let owner = extract_address_from_topic(log, 1, "owner")?;
// Extract int24 tickLower from topic2 (stored as a 32-byte padded value)
let tick_lower = match log.topics.get(2).and_then(|t| t.as_ref()) {
Some(topic) => {
let tick_lower_bytes: [u8; 32] = topic.as_ref().try_into()?;
i32::from_be_bytes(tick_lower_bytes[28..32].try_into()?)
}
None => anyhow::bail!("Missing tickLower in topic2 when parsing burn event"),
};
// Extract int24 tickUpper from topic3 (stored as a 32-byte padded value)
let tick_upper = match log.topics.get(3).and_then(|t| t.as_ref()) {
Some(topic) => {
let tick_upper_bytes: [u8; 32] = topic.as_ref().try_into()?;
i32::from_be_bytes(tick_upper_bytes[28..32].try_into()?)
}
None => anyhow::bail!("Missing tickUpper in topic3 when parsing burn event"),
};
if let Some(data) = &log.data {
let data_bytes = data.as_ref();
// Validate if data contains 3 parameters of 32 bytes each
if data_bytes.len() < 3 * 32 {
anyhow::bail!("Burn event data is too short");
}View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the log's topic0 matches the Uniswap V3 Burn signature 0x0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c before calling the parser
- Check `log.topics.len() >= 3` in your ingestion pipeline and skip/flag logs with fewer topics rather than passing them to the parser
- Re-fetch the log from HyperSync — upstream indexers occasionally return incomplete topic arrays; a fresh query usually restores all 3 topics
- If indexing a fork whose Burn event indexes fewer parameters, write a dedicated parser matching that fork's ABI
Example fix
// before: passing any Burn-topic log straight to the parser
let event = parse_burn_event_hypersync(dex, &log)?;
// after: validate topic count first
const BURN_TOPIC: &str = "0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c";
if log.topics.len() < 3 {
anyhow::bail!("burn log has {} topics, expected 3 — skipping malformed log", log.topics.len());
}
if !log.topics[0].to_string().contains(BURN_TOPIC) {
anyhow::bail!("not a Uniswap V3 Burn event");
}
let event = parse_burn_event_hypersync(dex, &log)?; Defensive patterns
Strategy: validation
Validate before calling
const BURN_TOPIC: &str = "0c396cd989a39f4459b5fa1aed6a9a8dcdbc45908acfd67e028cd568da98982c";
pub fn can_parse_burn(log: &HypersyncLog) -> bool {
let topic_ok = log.topics.first()
.and_then(|t| t.as_ref())
.map(|t| t.to_string().contains(BURN_TOPIC))
.unwrap_or(false);
topic_ok && log.topics.len() >= 3
} Type guard
fn has_burn_topics(log: &HypersyncLog) -> bool {
log.topics.len() >= 3
&& log.topics[1..3].iter().all(|t| t.as_ref().map(|b| b.len() == 32).unwrap_or(false))
} Try / catch
match parse_burn_event_hypersync(dex, &log) {
Ok(event) => store(event),
Err(e) if e.to_string().contains("Missing tick") => {
tracing::warn!("burn log missing indexed tick topics — malformed or non-standard log; skipping");
}
Err(e) => return Err(e),
} Prevention
- Filter HyperSync queries by the exact Burn topic0 so only well-formed Burn logs reach the parser
- Check topics.len() >= 3 before invoking the parser and skip shorter logs
- Re-fetch logs with missing topics — indexer gaps are usually transient
- For forked pools with different indexed layouts, write a dedicated parser matching that ABI
When it happens
Trigger: Calling parse_burn_event_hypersync with a HyperSync log whose `topics` array has fewer than 3 entries — e.g. an anonymous or non-standard Burn-like event, a log from a different event type routed by mistake, or a partially indexed log missing indexed parameters.
Common situations: Indexing forked Uniswap V3 pools whose Burn event has different indexed-parameter layout; HyperSync queries that filter on the wrong topic0 but return shorter-topic logs; misrouting Mint/Modge-like events with fewer topics into the Burn parser; upstream indexer gaps producing incomplete log objects.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Swap event data is too short
- Failed to decode swap event data: {e}
- Missing tickLower in topic2 when parsing collect event
- Missing tickUpper in topic3 when parsing collect event
- SetFeeProtocol event data is too short
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/7715509ae7fd3f7f.
Report an issue: GitHub.