nautechsystems/nautilus_trader · error
RPC positions do not match the complete HyperSync topology:
Error message
RPC positions do not match the complete HyperSync topology: expected {} positions, received {} What it means
After replaying HyperSync events and fetching the on-chain RPC snapshot, validate_rpc_snapshot_topology asserts the RPC-returned positions exactly equal the positions derived from event replay (same owner/tick-range keys and liquidity). A mismatch means event replay and on-chain state disagree, so the snapshot is rejected rather than restored.
Source
Thrown at crates/adapters/blockchain/src/data/core.rs:2113
position.liquidity,
)
})
.collect();
let actual_positions: AHashMap<_, _> = snapshot
.positions
.iter()
.map(|position| {
(
(position.owner, position.tick_lower, position.tick_upper),
position.liquidity,
)
})
.collect();
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() {View on GitHub (pinned to 18893faf8b)
Solutions
- Compare expected vs received counts and find the missing/extra positions; verify HyperSync stream coverage from pool creation_block (or from_position) to to_block with no gaps.
- Re-run bootstrap to a stable, recent block and with an archive-capable RPC to rule out reorgs or non-archive state misses.
- Check that mint/burn event signatures in the DEX config match the pool's actual contract so no liquidity events are dropped as unexpected.
- If new DEX variants emit extra liquidity-affecting events, extend process_pool_mint_event/burn handling so replay state includes them.
Example fix
// before
let from_block = from_position.map_or(profiler.pool.creation_block, |block_position| block_position.number);
// after (ensure full-history replay when topology validation fails)
let from_block = from_position
.filter(|bp| profiler.is_initialized)
.map_or(profiler.pool.creation_block, |block_position| block_position.number); Defensive patterns
Strategy: retry
Validate before calling
// Pre-check: replay from the pool's creation block so no liquidity events are missed
let from_block = from_position.filter(|_| profiler.is_initialized)
.map_or(pool.creation_block, |bp| bp.number);
anyhow::ensure!(from_block <= pool.creation_block || profiler.is_initialized,
"replay start {} may skip events; topology validation would fail", from_block); Try / catch
match attempt_bootstrap(from_position).await {
Err(e) if e.to_string().contains("do not match the complete HyperSync topology") => {
// retry once with full replay from pool.creation_block
attempt_bootstrap(None).await
}
other => other,
} Prevention
- Use archive-capable RPC endpoints for historical snapshot blocks.
- Ensure HyperSync stream coverage has no block gaps from from_block to to_block.
- Verify DEX mint/burn signature configs match the actual pool contract's events.
- Re-run bootstrap after detected chain reorgs.
When it happens
Trigger: construct_pool_profiler_from_hypersync_rpc calls validate_rpc_snapshot_topology and the fetched snapshot's position set differs from profiler.get_all_positions() — counts differ, keys differ, or (implied by the len check) duplicate position keys collapse in the map.
Common situations: Missed or malformed Mint/Burn logs during HyperSync replay (gaps in stream coverage); using a non-archive or reorg-affected RPC block for the snapshot; replaying from a wrong from_block so some liquidity events were never processed; a pool with liquidity events between the replay target block and the RPC query block.
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
- unexpected event signature in bootstrap_latest_pool_profiler
- RPC snapshot contains duplicate ticks
- Unsupported `OrderSide` for Binance: {value:?}
- invalid OrderSide: must be Buy or Sell, was {side}
- Finalized block {} does not contain transaction {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/546ba25f005bc94f.
Report an issue: GitHub.