actix/actix · critical · panic

Mocker actor used before set

Error message

Mocker actor used before set

What it means

Mocker<T> is a test-double actor that wraps another actor so messages can be intercepted. It has no meaningful Default implementation: the only `default()` body is a panic, because a Mocker must be explicitly configured (via `Mocker::<T>::run(...)` or the `mock`/`set` mechanism) before the actor system tries to create one. When the system constructs a Mocker through `Default::default()` — typically via `SystemService::start_service` or `ArbiterService` registries — the panic fires, meaning the mock was never set up.

Solutions

  1. Call `Mocker::<TargetActor>::run(mock_fn, |_, addr| { ... })` (or the equivalent `run_with` helper) so the mock is installed before the actor is resolved.
  2. Do not resolve Mocker via `from_registry()`/`start_service()` expecting a default; it intentionally has no default instance.
  3. If you did not intend a mock, use the real actor type instead of Mocker<T>.
  4. Check test setup order: mock must be set before any code starts the service.

Example fix

// before
let addr = Mocker::<MyActor>::from_registry();

// after
Mocker::<MyActor>::run(|msg, ctx| { ...mock behavior... }, |_, addr| {
    // use addr inside this scope
});
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the mock is installed before resolving the service
let installed = /* your test registry flag */;
assert!(installed, "call Mocker::<T>::run(...) before from_registry()");

Try / catch

// Panics are not catchable in normal Rust code; ensure setup ordering instead.
#[test]
#[should_panic(expected = "Mocker actor used before set")]
fn mocker_without_setup_panics() { let _ = Mocker::<MyActor>::from_registry(); }

Prevention

When it happens

Trigger: Resolving Mocker<T> as a SystemService or ArbiterService (e.g. `Mocker::<MyActor>::from_registry()` or `start_service()`) without first calling the mock setup API (`Mocker::<MyActor>::run(...)` / providing a boxed mock handler). Any code path that requires `Default::default()` for Mocker<T>.

Common situations: Writing actix unit tests where the developer registers/looks up the mocker service before `run()`; copy-pasting real actor service code but swapping in Mocker without calling its setup; upgrading actix where test helpers changed order of initialization.

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 actix/actix@36e5d97e41 (2026-09-11). Data as JSON: /api/errors/bde15efa9574c35a. Report an issue: GitHub.

Appendix: source

Thrown at actix/src/actors/mocker.rs:59

impl<T: Unpin> Mocker<T> {
    #[allow(clippy::type_complexity)]
    pub fn mock(
        mock: Box<dyn FnMut(Box<dyn Any>, &mut Context<Mocker<T>>) -> Box<dyn Any>>,
    ) -> Mocker<T> {
        Mocker::<T> {
            phantom: PhantomData,
            mock,
        }
    }
}

impl<T: SystemService> SystemService for Mocker<T> {}
impl<T: ArbiterService> ArbiterService for Mocker<T> {}
impl<T: Unpin> Supervised for Mocker<T> {}

impl<T: Unpin> Default for Mocker<T> {
    fn default() -> Self {
        panic!("Mocker actor used before set")
    }
}

impl<T: Sized + Unpin + 'static> Actor for Mocker<T> {
    type Context = Context<Self>;
}

impl<M: 'static, T: Sized + Unpin + 'static> Handler<M> for Mocker<T>
where
    M: Message,
    <M as Message>::Result: MessageResponse<Mocker<T>, M>,
{
    type Result = M::Result;
    fn handle(&mut self, msg: M, ctx: &mut Self::Context) -> M::Result {
        let mut ret = (self.mock)(Box::new(msg), ctx);
        let out = ret
            .downcast_mut::<Option<M::Result>>()
            .expect("wrong return type for message")

View on GitHub (pinned to 36e5d97e41)