nautechsystems/nautilus_trader · error
Python on_degrade failed: {e}
Error message
Python on_degrade failed: {e} What it means
PyExecutionAlgorithm's DataActor on_degrade dispatches the Python `on_degrade` callback; any Python exception is re-wrapped with this anyhow message. Degrade is invoked when the system enters a degraded (reduced-capability) state, so a failure here means the Python degraded-mode handler raised.
Source
Thrown at crates/trading/src/python/algorithm.rs:575
ExecutionAlgorithm::on_resume(self)?;
self.dispatch_no_args("on_resume")
.map_err(|e| anyhow::anyhow!("Python on_resume failed: {e}"))
}
fn on_reset(&mut self) -> anyhow::Result<()> {
ExecutionAlgorithm::on_reset(self)?;
self.dispatch_no_args("on_reset")
.map_err(|e| anyhow::anyhow!("Python on_reset failed: {e}"))
}
fn on_dispose(&mut self) -> anyhow::Result<()> {
self.dispatch_no_args("on_dispose")
.map_err(|e| anyhow::anyhow!("Python on_dispose failed: {e}"))
}
fn on_degrade(&mut self) -> anyhow::Result<()> {
self.dispatch_no_args("on_degrade")
.map_err(|e| anyhow::anyhow!("Python on_degrade failed: {e}"))
}
fn on_fault(&mut self) -> anyhow::Result<()> {
self.dispatch_no_args("on_fault")
.map_err(|e| anyhow::anyhow!("Python on_fault failed: {e}"))
}
fn on_time_event(&mut self, event: &TimeEvent) -> anyhow::Result<()> {
ExecutionAlgorithm::on_time_event(self, event)?;
self.dispatch_time_event(event)
.map_err(|e| anyhow::anyhow!("Python on_time_event failed: {e}"))
}
fn on_signal(&mut self, signal: &Signal) -> anyhow::Result<()> {
self.dispatch_on_signal(signal)
.map_err(|e| anyhow::anyhow!("Python on_signal failed: {e}"))
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Read the chained `{e}` traceback and fix the Python on_degrade implementation.
- Make on_degrade not depend on the resources whose failure caused the degradation.
- Guard state access so degrade works even if called before/after other lifecycle stages.
- Verify the zero-arg `def on_degrade(self)` signature.
Example fix
// before
def on_degrade(self):
self.conn.pause() # conn already dead
// after
def on_degrade(self):
self.degraded = True # local flag only; reconnect on_resume Defensive patterns
Strategy: try-catch
Validate before calling
# Python: degrade must not depend on live connections assert hasattr(self, "degraded"), "degrade flag not initialized in __init__"
Try / catch
if let Err(e) = actor.on_degrade() {
log::error!("python on_degrade failed: {e:#}");
// treat as fault if the actor cannot even enter degraded mode
} Prevention
- Make on_degrade only flip local state flags; do recovery work in on_resume.
- Initialize the degraded flag in __init__ so degrade works at any lifecycle stage.
- Chaos-test connection-loss paths so on_degrade runs with the failing resource already dead.
When it happens
Trigger: Calling on_degrade when the Python on_degrade raises — e.g. the callback assumes resources that are already unavailable, or wrong no-arg signature.
Common situations: Degrade triggered by connection loss where the handler then tries to use that same dead connection; typo'd or mis-signed degrade hook; degrade fired before on_start initialized state.
Related errors
- Python on_start failed: {e}
- Python on_stop failed: {e}
- Python on_resume failed: {e}
- Python on_reset failed: {e}
- Python on_dispose failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/269080c9f0926ee6.
Report an issue: GitHub.