nautechsystems/nautilus_trader · error

DataActor must be registered before accessing cache

Error message

DataActor must be registered before accessing cache

What it means

DataActor::cache_ref borrows the shared Cache for reading, but the cache handle is only populated when the actor is registered with a Trader/Node. Calling it before registration panics with this message, enforcing the actor lifecycle: no cache access before registration.

Source

Thrown at crates/common/src/actor/data_actor.rs:219

    /// Panics if the actor has not yet been registered.
    fn clock_rc(&self) -> Rc<RefCell<dyn Clock>> {
        self.core()
            .clock
            .as_ref()
            .expect("DataActor must be registered before accessing clock")
            .clone()
    }

    /// Returns a read-only cache borrow.
    ///
    /// # Panics
    ///
    /// Panics if the actor has not yet been registered.
    fn cache_ref(&self) -> Ref<'_, Cache> {
        self.core()
            .cache
            .as_ref()
            .expect("DataActor must be registered before accessing cache")
            .borrow()
    }

    /// Returns a clone of the reference-counted cache.
    ///
    /// # Panics
    ///
    /// Panics if the actor has not yet been registered.
    fn cache_rc(&self) -> Rc<RefCell<Cache>> {
        self.core()
            .cache
            .as_ref()
            .expect("DataActor must be registered before accessing cache")
            .clone()
    }
}

/// Defines lifecycle callbacks, data handlers, and subscription/request

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Access the cache only from lifecycle callbacks (on_start and later) that run after registration
  2. Register the actor before invoking any cache-dependent method
  3. In tests, register the actor with a test harness/kernel (or populate the core's cache) before exercising handlers

Example fix

// before
let prices = actor.cache_ref().prices(...); // panics if called pre-registration
// after
// inside on_start / on_data, post-registration:
let prices = self.cache_ref().prices(...);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure registration completed before any cache access:
// e.g. call sites only in on_start/on_data, never in new().
fn ensure_registered(registered: bool) {
    assert!(registered, "cache access requires registration");
}

Try / catch

// Panics are not catchable; enforce ordering by only reading cache in lifecycle callbacks:
fn on_start(&mut self) {
    let cache = self.cache_ref(); // safe here
}

Prevention

When it happens

Trigger: Calling cache_ref() (directly or via helpers like cache_read) from the actor's constructor, before trader.add_actor/node registration, or in tests that build a bare DataActor without registering it.

Common situations: Attempting to read market data/prices in actor initialization code; unit tests instantiating the actor manually and calling data handlers without simulating registration; calling on_start-style logic too early.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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