nautechsystems/nautilus_trader · error · anyhow::Error

Failed to initialize tracing subscriber: {e}

Error message

Failed to initialize tracing subscriber: {e}

What it means

`init_tracing` builds a fmt tracing subscriber with the Nautilus formatter and installs it via `tracing::subscriber::set_global_default`. The global default subscriber can only be set once per process, so a second initialization attempt returns this error wrapping the tracing SetGlobalDefaultError.

Source

Thrown at crates/common/src/logging/bridge.rs:113

/// # Errors
///
/// Returns an error if the tracing subscriber has already been initialized.
pub fn init_tracing() -> anyhow::Result<()> {
    if TRACING_INITIALIZED.load(Ordering::SeqCst) {
        anyhow::bail!("Tracing subscriber already initialized");
    }

    let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new("warn"));

    let subscriber = tracing_subscriber::registry()
        .with(filter)
        .with(fmt::layer().event_format(NautilusFormatter));

    // Install only the tracing subscriber here. Python logging manages the
    // global `log` logger separately, so we must not claim it through
    // SubscriberInitExt::try_init().
    tracing::subscriber::set_global_default(subscriber)
        .map_err(|e| anyhow::anyhow!("Failed to initialize tracing subscriber: {e}"))?;

    TRACING_INITIALIZED.store(true, Ordering::SeqCst);
    Ok(())
}

#[cfg(test)]
mod tests {
    use rstest::rstest;

    use super::*;

    #[rstest]
    fn test_tracing_is_initialized_returns_bool() {
        let _ = tracing_is_initialized();
    }
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Call init_tracing only once per process; gate it behind a OnceLock/once flag or the library's existing TRACING_INITIALIZED check.
  2. Check the returned error's source for 'a global default trace dispatcher has already been set' to detect double init.
  3. Use tracing::subscriber::with_default (thread-local) or set_default in scoped contexts instead of global installation for tests.
  4. Ensure the host application does not install its own global subscriber before nautilus init.

Example fix

// before
init_tracing(level)?; // called in setup and again in each test
// after
static INIT: OnceLock<()> = OnceLock::new();
if INIT.set(()).is_ok() {
    init_tracing(level)?;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust: guard against double global subscriber install
static TRACING_DONE: OnceLock<()> = OnceLock::new();
if TRACING_DONE.get().is_some() { return Ok(()); }

Type guard

fn tracing_ready() -> bool { TRACING_INITIALIZED.load(Ordering::SeqCst) }

Try / catch

if let Err(e) = init_tracing(level) {
    if e.to_string().contains("already been set") { debug!("tracing already installed"); }
    else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling init_tracing (or a higher-level init that reaches it) more than once in the same process — e.g. a test harness and the code under test both calling it, multiple subsystems initializing logging, or re-running after a previous call already flipped TRACING_INITIALIZED.

Common situations: Running multiple tests in one process that each call init; embedding nautilus into an app that already installed its own tracing subscriber; double-start of a runtime/node; mixing init_tracing with another crate that claims the global subscriber.

Related errors


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