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
- Read the Python traceback in the error to pinpoint the failure inside on_fault.
- Keep on_fault minimal and fully guarded in try/except so fault handling never itself raises.
- Verify emergency actions (position flattening, notifications) handle unavailable dependencies gracefully.
- 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
- Keep on_fault minimal and every statement guarded — a raising fault handler masks the root cause.
- Do not rely on external services (notification clients) inside on_fault; use local logging fallback.
- Deliberately trigger faults in staging to validate the handler.
- Alert on fault-handler exceptions so they are never silently ignored.
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
- Python on_stop failed: {e}
- Python on_resume failed: {e}
- Python on_reset failed: {e}
- Python on_dispose failed: {e}
- Python on_degrade failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/bfd138854a72eeb2.
Report an issue: GitHub.