{"record":{"id":"85900406940eb918","repo":"nautechsystems/nautilus_trader","slug":"global-logging-sender-was-already-published","errorCode":null,"errorMessage":"Global logging sender was already published","messagePattern":"Global logging sender was already published","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/common/src/logging/logger.rs","lineNumber":987,"sourceCode":"\n        #[cfg(all(test, not(all(feature = \"simulation\", madsim))))]\n        if let Some(hook) = INIT_PUBLISH_HOOK.lock().take() {\n            let _ = hook.reached.send(());\n            let _ = hook.resume.recv();\n        }\n\n        // Store the sender globally so additional guards can be created\n        if let Err(tx) = LOGGER_TX.set(tx) {\n            #[cfg(not(all(feature = \"simulation\", madsim)))]\n            {\n                let _ = tx.send(LogEvent::Close);\n                if handle.thread().id() != std::thread::current().id() {\n                    let _ = handle.join();\n                }\n            }\n            drop(tx);\n            *lifecycle = LoggerLifecycle::Terminated;\n            anyhow::bail!(\"Global logging sender was already published\");\n        }\n\n        if config.bypass_logging {\n            super::logging_set_bypass();\n        }\n\n        let is_colored = config.is_colored;\n\n        let print_config = config.print_config;\n        if print_config {\n            println!(\"STATIC_MAX_LEVEL={STATIC_MAX_LEVEL}\");\n            println!(\"Logger initialized with {config:?} {file_config:?}\");\n        }\n\n        #[cfg(not(all(feature = \"simulation\", madsim)))]\n        {\n            // Store the handle globally\n            let mut handle_guard = LOGGER_HANDLE.lock();","sourceCodeStart":969,"sourceCodeEnd":1005,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/logging/logger.rs#L969-L1005","documentation":"During logging initialization, the global LOGGER_TX channel sender is published via a once-only slot. If initialization detects the sender was already published (a prior init published it) while the current init cannot proceed, it tears down the threads it started, marks the lifecycle Terminated, and bails. This guards against double publication of the global sender.","triggerScenarios":"Calling the logging init function concurrently or twice when the first init already stored the global sender in LOGGER_TX but the lifecycle state was reset or raced, so the second init sees LOGGER_TX already set.","commonSituations":"Multi-threaded startup where two threads race to initialize logging, or repeated init calls after a partially failed earlier initialization.","solutions":["Ensure logging init is called exactly once, guarded by a `std::sync::Once` or equivalent, before spawning threads that may also init.","Check for a prior partial init failure: if init errored previously, the process state may be inconsistent — restart or restructure to avoid retrying init.","Serialize initialization behind a mutex/once cell in application startup code.","If this occurs in tests, run logging-init tests single-threaded (e.g. `#[test]` with a global lock or serial test runner)."],"exampleFix":"// before\nstd::thread::spawn(|| logging_init(cfg).unwrap());\nlogging_init(cfg).unwrap();\n// after\nstatic INIT: std::sync::Once = std::sync::Once::new();\nINIT.call_once(|| logging_init(cfg).expect(\"logging init\"));","handlingStrategy":"try-catch","validationCode":"static LOG_INIT: std::sync::Once = std::sync::Once::new();\nfn ensure_log_init(cfg: LoggingConfig) { LOG_INIT.call_once(|| logging_init(cfg).expect(\"logging init\")); }","typeGuard":null,"tryCatchPattern":"if let Err(e) = logging_init(cfg) {\n    if e.to_string().contains(\"already published\") {\n        // another thread won the init race; treat as success\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["Guard logging init with std::sync::Once in multi-threaded startup.","Never spawn threads that can call logging init concurrently.","Treat 'already published' as an idempotent success in catch handlers."],"tags":["logging","concurrency","global-state","rust"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}