nautechsystems/nautilus_trader · error
RPC snapshot contains duplicate ticks
Error message
RPC snapshot contains duplicate ticks
What it means
The on-chain snapshot's ticks are collected into a map keyed by tick value; if the resulting map is smaller than the raw tick list, the RPC returned the same tick more than once. Since a Uniswap V3 tick bitmap has unique entries, duplicates indicate a malformed snapshot, so validation bails before restore.
Source
Thrown at crates/adapters/blockchain/src/data/core.rs:2127
if actual_positions.len() != snapshot.positions.len()
|| actual_positions != expected_positions
{
anyhow::bail!(
"RPC positions do not match the complete HyperSync topology: expected {} positions, received {}",
expected_positions.len(),
actual_positions.len()
);
}
let actual_ticks: AHashMap<_, _> = snapshot
.ticks
.iter()
.map(|tick| (tick.value, tick))
.collect();
if actual_ticks.len() != snapshot.ticks.len() {
anyhow::bail!("RPC snapshot contains duplicate ticks");
}
let expected_tick_values = profiler.get_active_tick_values();
if actual_ticks.len() != expected_tick_values.len() {
anyhow::bail!(
"RPC ticks do not match the complete HyperSync topology: expected {} ticks, received {}",
expected_tick_values.len(),
actual_ticks.len()
);
}
for tick_value in expected_tick_values {
let expected_tick = profiler
.get_tick(tick_value)
.with_context(|| format!("missing replay tick {tick_value}"))?;
let actual_tick = actual_ticks
.get(&tick_value)
.with_context(|| format!("RPC snapshot omitted tick {tick_value}"))?;View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect snapshot.ticks for the duplicated tick values and check the fetch_snapshot implementation that produced them (pagination/Multicall chunking may double-count a boundary tick).
- Ensure the ticks requested from the pool contract are derived from the profiler's distinct active tick values (get_active_tick_values) without overlap.
- Upgrade/fix the univ3_pool snapshot reader for the specific DEX fork if its tick queries return duplicated entries.
- Re-run bootstrap against a different RPC endpoint to rule out endpoint-specific malformed responses.
Example fix
// before let requested_ticks = ticks_from_raw_query; // may contain duplicates from overlapping chunks // after let requested_ticks: Vec<_> = requested_ticks.into_iter().map(|t| (t.value, t)).collect::<AHashMap<_,_>>().into_values().collect();
Defensive patterns
Strategy: try-catch
Validate before calling
// Deduplicate/detect duplicate ticks in a snapshot before use
let unique: std::collections::HashSet<i32> = snapshot.ticks.iter().map(|t| t.value).collect();
if unique.len() != snapshot.ticks.len() {
// snapshot is malformed; do not restore
} Type guard
fn has_unique_ticks(snapshot: &PoolSnapshot) -> bool {
let mut seen = std::collections::HashSet::new();
snapshot.ticks.iter().all(|t| seen.insert(t.value))
} Try / catch
match bootstrap_result {
Err(e) if e.to_string().contains("duplicate ticks") => {
log::error!("RPC snapshot malformed (duplicate ticks): {e:#}");
// re-fetch snapshot from a different endpoint or fail the bootstrap
}
other => other?,
} Prevention
- Derive requested ticks from the profiler's distinct active tick values.
- Fix chunked/Multicall tick fetches to avoid duplicating boundary ticks.
- Validate snapshots (uniqueness + count) before restore_from_snapshot in any custom fetch path.
When it happens
Trigger: validate_rpc_snapshot_topology (invoked from construct_pool_profiler_from_hypersync_rpc after fetching the snapshot) receives a PoolSnapshot whose `ticks` vec contains two or more entries with the same `value`.
Common situations: A buggy or misbehaving RPC/contract reader aggregating ticks incorrectly; contract fetch_snapshot returning overlapping tick ranges (e.g. tick values not normalized by tick spacing); a custom fork's Multicall response parsed twice into the tick list.
Related errors
- RPC positions do not match the complete HyperSync topology:
- Invalid tick range: {tick_lower} >= {tick_upper}
- Ticks {tick_lower} and {tick_upper} must be multiples of the
- Invalid tick bounds for {tick_lower} and {tick_upper}
- Wallet balance snapshot contains duplicate token addresses:
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/26bbe1dc7ddef500.
Report an issue: GitHub.