nautechsystems/nautilus_trader · error

Python on_fault failed: {e}

Error message

Python on_fault failed: {e}

What it means

Raised by the Rust `DataActor` bridge when the Python actor's `on_fault()` callback raises an exception. `dispatch_on_fault()` forwards to Python and the exception is rewrapped with this message. on_fault handles the transition into a faulted (non-recoverable) state.

Source

Thrown at crates/common/src/python/actor.rs:1050

    fn on_reset(&mut self) -> anyhow::Result<()> {
        self.dispatch_on_reset()
            .map_err(|e| anyhow::anyhow!("Python on_reset failed: {e}"))
    }

    fn on_dispose(&mut self) -> anyhow::Result<()> {
        self.dispatch_on_dispose()
            .map_err(|e| anyhow::anyhow!("Python on_dispose failed: {e}"))
    }

    fn on_degrade(&mut self) -> anyhow::Result<()> {
        self.dispatch_on_degrade()
            .map_err(|e| anyhow::anyhow!("Python on_degrade failed: {e}"))
    }

    fn on_fault(&mut self) -> anyhow::Result<()> {
        self.dispatch_on_fault()
            .map_err(|e| anyhow::anyhow!("Python on_fault failed: {e}"))
    }

    fn on_save(&self) -> anyhow::Result<IndexMap<String, Vec<u8>>> {
        self.dispatch_on_save()
            .map_err(|e| anyhow::anyhow!("Python on_save failed: {e}"))
    }

    fn on_load(&mut self, state: IndexMap<String, Vec<u8>>) -> anyhow::Result<()> {
        self.dispatch_on_load(&state)
            .map_err(|e| anyhow::anyhow!("Python on_load failed: {e}"))
    }

    fn on_time_event(&mut self, event: &TimeEvent) -> anyhow::Result<()> {
        self.dispatch_on_time_event(event.clone())
            .map_err(|e| anyhow::anyhow!("Python on_time_event failed: {e}"))
    }

    #[allow(unused_variables)]

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the Python traceback in the error to pinpoint the failure inside on_fault.
  2. Keep on_fault minimal and fully guarded in try/except so fault handling never itself raises.
  3. Verify emergency actions (position flattening, notifications) handle unavailable dependencies gracefully.
  4. Trigger a fault deliberately in staging to validate the handler.

Example fix

// before (Python)
def on_fault(self):
    self.close_all_positions()

// after
def on_fault(self):
    try:
        self.close_all_positions()
    except Exception as e:
        self.log.error(f"emergency flatten failed: {e}")
Defensive patterns

Strategy: try-catch

Validate before calling

# fault-path readiness check
assert callable(getattr(self, 'close_all_positions', None)), 'emergency handler missing'

Type guard

def fault_ready(actor):
    return callable(getattr(actor, 'on_fault', None))

Try / catch

def on_fault(self):
    try:
        ...  # emergency actions
    except Exception as e:
        self.log.critical(f"fault handler failed: {e}")

Prevention

When it happens

Trigger: Any exception in the user's Python `on_fault`: emergency flattening positions and hitting an API error, logging to an unavailable sink, or dereferencing attributes that are None during the fault path.

Common situations: Fault handling in live trading where the fault handler itself is buggy, masking the original fault; on_fault trying to send notifications through a client that is down.

Related errors


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