nautechsystems/nautilus_trader · error · anyhow::Error

Failed to create LogGuard from global sender

Error message

Failed to create LogGuard from global sender

What it means

In the non-(simulation+madsim) init path, after spawning the logger thread and setting LOGGING_INITIALIZED, the code creates the LogGuard that owns the global sender via `LogGuard::new_locked()`. If that returns None (guard state could not be established from the just-created global sender) it aborts with this error — logging was configured but a valid owner handle could not be produced.

Source

Thrown at crates/common/src/logging/logger.rs:1035

            // and force the bypass flag so subsequent log calls no-op without
            // SendError noise.
            let _ = (trader_id, instance_id, config, file_config, rx);
            super::logging_set_bypass();
        }

        let max_level = log::LevelFilter::Trace;
        set_max_level(max_level);

        if print_config {
            println!("Logger set as `log` implementation with max level {max_level}");
        }

        super::LOGGING_INITIALIZED.store(true, Ordering::SeqCst);
        super::LOGGING_COLORED.store(is_colored, Ordering::SeqCst);
        *lifecycle = LoggerLifecycle::Running;

        LogGuard::new_locked()
            .ok_or_else(|| anyhow::anyhow!("Failed to create LogGuard from global sender"))
    }

    #[cfg(not(all(feature = "simulation", madsim)))]
    #[expect(clippy::needless_pass_by_value)]
    fn handle_messages(
        trader_id: String,
        instance_id: String,
        config: LoggerConfig,
        file_config: FileWriterConfig,
        rx: std::sync::mpsc::Receiver<LogEvent>,
    ) {
        let LoggerConfig {
            stdout_level,
            fileout_level,
            component_level: _,
            module_level: _,
            log_components_only: _,
            is_colored,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Initialize logging once, early, on the main thread before any fork/thread spawn.
  2. If using multiprocessing/fork, initialize logging in each child after fork rather than inheriting state.
  3. Check for earlier panics or poisoned statics in the logging module; restart the process if globals are inconsistent.
  4. Ensure only one call path initializes logging (avoid both Python init_logging and Rust init racing).

Example fix

// before
spawn_worker();        // forks after logging init
init_logging(...)?;    // child hits failed guard here
// after
spawn_worker_with(|| {
    let guard = init_logging(...)?; // init inside child
    run(guard)
});
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust: detect inconsistent logging statics before init
if LOGGING_INITIALIZED.load(Ordering::SeqCst) && LOGGER_LIFECYCLE.lock() != Running {
    // statics inconsistent; avoid init path that builds a guard from sender
}

Type guard

fn guard_available() -> bool { LogGuard::peek_locked().is_some() }

Try / catch

let guard = LogGuard::new_locked().ok_or_else(|| {
    anyhow::anyhow!("Failed to create LogGuard from global sender; restart process")
})?;

Prevention

When it happens

Trigger: First-time logger initialization where LogGuard::new_locked() fails to attach to the global sender — typically caused by broken internal static state (e.g. statics reset after fork, re-entrant init from a signal/atexit handler, or a prior init panicking mid-way leaving inconsistent globals).

Common situations: Fork-after-init in multiprocess setups (child inherits inconsistent statics); double init racing in threads without synchronization; embedding nautilus in a runtime that re-executes module init; OOM or panic during logger thread startup.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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