nautechsystems/nautilus_trader · error

Python on_degrade failed: {e}

Error message

Python on_degrade failed: {e}

What it means

The strategy's Python-level `on_degrade` callback raised an exception. The Rust `DataActor`/strategy wrapper calls `dispatch_on_degrade()` (crates/trading/src/python/strategy.rs:370), which invokes `on_degrade` on the Python instance via `call_method0`; any Python exception is converted to a `PyResult` error and re-wrapped with this anyhow message. The message text interpolates the underlying Python exception (`{e}`), so the actual cause is whatever traceback the user's `on_degrade` raised.

Source

Thrown at crates/trading/src/python/strategy.rs:1086

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

    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<()> {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the interpolated `{e}` text for the underlying Python exception and fix the bug inside your Python `on_degrade` implementation.
  2. Wrap the body of `on_degrade` in try/except, log, and perform defensive cleanup so degradation itself never raises.
  3. Verify the strategy class actually defines `on_degrade` (not just inherits from a base class whose signature changed).
  4. Guard against degraded dependencies (e.g. check client is not None) before using them in the handler.

Example fix

// before (Python)
def on_degrade(self):
    self.client.reset()  # raises if client is None

// after
def on_degrade(self):
    if self.client is None:
        self.log.warning("client already unavailable; nothing to reset")
        return
    try:
        self.client.reset()
    except Exception as e:
        self.log.error(f"degrade cleanup failed: {e}")
Defensive patterns

Strategy: try-catch

Validate before calling

def _check_degrade_safe(strategy):
    import inspect
    fn = getattr(strategy, "on_degrade", None)
    return callable(fn) and len(inspect.signature(fn).parameters) == 1

Type guard

def has_hook(obj, name):
    return callable(getattr(obj, name, None))

Try / catch

try:
    self.on_degrade()
except Exception as e:
    self.log.error(f"on_degrade raised: {e}")  # never let lifecycle hooks escape

Prevention

When it happens

Trigger: The node transitions to a DEGRADED state and the framework calls `on_degrade()` on the strategy; the user-implemented Python `on_degrade` method raises any exception (e.g. referencing an attribute that is None because an upstream dependency degraded, or calling an API in an inconsistent state).

Common situations: Degradation handlers that try to close or reset connections to services that are already unreachable; `on_degrade` code assuming `self.cache`/`self.portfolio` state that is not present; typos or signature changes in the Python method; raising deliberately inside `on_degrade` to signal failure but expecting it to be swallowed.

Related errors


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