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

  1. 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.
  2. Re-run bootstrap to a stable, recent block and with an archive-capable RPC to rule out reorgs or non-archive state misses.
  3. Check that mint/burn event signatures in the DEX config match the pool's actual contract so no liquidity events are dropped as unexpected.
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/546ba25f005bc94f. Report an issue: GitHub.