nautechsystems/nautilus_trader · error

record anchor

Error message

record anchor

What it means

Test panic from `.expect("record anchor")` on `EventStoreWriter::record_snapshot_anchor`, which returns `EventStoreError::Closed` if halted/shut down, a Backend stall error if enqueue or the ack round-trip exceeds `halt_threshold`, or a backend error while persisting the anchor. The method flushes pending entries first, then records the anchor at the durable high-watermark so it never points past committed state.

Source

Thrown at crates/event_store/src/writer/mod.rs:1878

        let (wrapper, shared) = SharedMemory::new();
        shared
            .lock()
            .open_run(manifest("run-anchor"))
            .expect("open");

        let writer = EventStoreWriter::spawn(
            Box::new(wrapper),
            get_atomic_clock_static(),
            noop_halt(),
            WriterConfig::default(),
        )
        .expect("spawn");

        writer.submit(entry_draft(10)).expect("submit first");
        writer.submit(entry_draft(11)).expect("submit second");
        let anchor = writer
            .record_snapshot_anchor("cache://position-snapshots/P-1/0", "blake3:abc")
            .expect("record anchor");

        let backend = shared.lock();
        assert_eq!(anchor.high_watermark, 2);
        assert_eq!(
            backend.latest_snapshot_anchor().expect("latest anchor"),
            Some(anchor),
        );
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure no halt was fired and the writer is still open before calling `record_snapshot_anchor`.
  2. Increase `halt_threshold` if flushing pending entries legitimately needs longer than the ack timeout.
  3. Check the returned `EventStoreError` string ("stalled", "ack channel disconnected", backend error) to locate the failing stage.
  4. Verify the backend's anchor persistence path (e.g. `record_snapshot_anchor` implementation) succeeds for the given blob_ref.

Example fix

// before
let anchor = writer.record_snapshot_anchor("cache://position-snapshots/P-1/0", "blake3:abc")
    .expect("record anchor");
// after
let anchor = writer.record_snapshot_anchor("cache://position-snapshots/P-1/0", "blake3:abc")
    .unwrap_or_else(|e| panic!("record anchor failed: {e:?}"));
Defensive patterns

Strategy: retry

Validate before calling

if halted.load(Ordering::Acquire) { return Err(EventStoreError::Closed); }
// ensure no outstanding submits likely to exceed halt_threshold before anchoring

Try / catch

match writer.record_snapshot_anchor(blob_ref, hash) {
    Ok(anchor) => cache.store(anchor),
    Err(EventStoreError::Closed) => log::warn!("writer halted/closed; anchor skipped"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling after a halt fired or the writer closed; the ack channel timing out because the writer thread cannot commit pending entries within `halt_threshold`; the ack channel disconnecting (writer thread died); the backend rejecting the anchor write.

Common situations: Recording an anchor while earlier submits are still pending and the backend is slow; calling on a halted writer; anchor blob_ref/content_hash handling triggering a backend persistence error.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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