nautechsystems/nautilus_trader · critical

Component '{id}' is already mutably borrowed. This would cre

Error message

Component '{id}' is already mutably borrowed. This would create aliasing mutable references (undefined behavior).

What it means

The global component registry enforces single mutable borrow of each registered component via a try_borrow flag. start_component first try_borrows the component; if it is already mutably borrowed (another lifecycle call in progress), it rejects with this message to prevent aliasing &mut references, which would be undefined behavior in Rust.

Source

Thrown at crates/common/src/component.rs:554

    component_ref
}

/// Safely calls `start()` on a component in the global registry.
///
/// # Errors
///
/// - Returns an error if the component is not found.
/// - Returns an error if the component is already borrowed.
/// - Returns an error if `start()` fails.
pub fn start_component(id: &Ustr) -> anyhow::Result<()> {
    let component_ref = with_component_registry(|registry| {
        let component_ref = registry
            .get(id)
            .ok_or_else(|| anyhow::anyhow!("Component '{id}' not found in global registry"))?;

        if !registry.try_borrow(*id) {
            anyhow::bail!(
                "Component '{id}' is already mutably borrowed. \
                 This would create aliasing mutable references (undefined behavior)."
            );
        }

        Ok::<_, anyhow::Error>(component_ref)
    })?;

    let _guard = BorrowGuard::new(*id);

    // SAFETY: Borrow tracking ensures exclusive access
    unsafe {
        let component = &mut *component_ref.get();
        component.start()
    }
}

/// Returns the state of a component in the global registry.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Never call start_component (or other lifecycle functions) on a component from within that component's own callbacks.
  2. Ensure the borrow is released before the next call: lifecycle helpers release on scope exit and on panic; check that no closure still holds the returned reference.
  3. Serialize lifecycle operations per component with your own lock/queue so only one runs at a time.
  4. Restructure so the component signals completion (e.g. via message/event) and the caller starts it afterwards, instead of nested calls.

Example fix

// before
fn on_start(&mut self) {
    start_component(&self.id()); // self is already borrowed -> UB guard fires
}
// after
fn on_start(&mut self) {
    // schedule external start instead of borrowing self
    self.msgbus.publish_start_request(&self.id());
}
Defensive patterns

Strategy: try-catch

Validate before calling

fn is_lifecycle_idle(component_id: &ComponentId) -> bool {
    // ensure no lifecycle task is in flight for this id before starting
    LIFECYCLE_IN_FLIGHT.get(component_id).map_or(true, |b| !*b)
}

Try / catch

match start_component(id) {
    Err(e) if e.to_string().contains("already mutably borrowed") => {
        log::warn!("component {id} busy; retrying after in-flight op");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling start_component for a component id while another lifecycle operation (start/stop/reset/dispose or component_state access that is still in scope) holds the borrow — e.g. calling start from inside the component's own start() callback, or concurrent start_component calls for the same id.

Common situations: Re-entrant lifecycle calls: a component's on_start handler calling start_component on itself; background threads triggering start while the main loop already borrowed it; nested strategies starting their parent; deadlock-avoidance tests.

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/f18d1faabec21dfd. Report an issue: GitHub.