{"record":{"id":"277f2388b5ad19ab","repo":"nautechsystems/nautilus_trader","slug":"logging-is-running-without-a-published-sender","errorCode":null,"errorMessage":"Logging is running without a published sender","messagePattern":"Logging is running without a published sender","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/common/src/logging/logger.rs","lineNumber":1304,"sourceCode":"/// # Errors\n///\n/// Returns an error if the sync request cannot be delivered or acknowledged.\npub fn sync_to_disk() -> anyhow::Result<()> {\n    #[cfg(all(feature = \"simulation\", madsim))]\n    {\n        Ok(())\n    }\n\n    #[cfg(not(all(feature = \"simulation\", madsim)))]\n    {\n        let lifecycle = LOGGER_LIFECYCLE.lock();\n\n        if *lifecycle != LoggerLifecycle::Running {\n            return Ok(());\n        }\n\n        let Some(tx) = LOGGER_TX.get() else {\n            anyhow::bail!(\"Logging is running without a published sender\");\n        };\n\n        sync_sender_to_disk(tx)\n    }\n}\n\n#[cfg(not(all(feature = \"simulation\", madsim)))]\nfn sync_sender_to_disk(tx: &std::sync::mpsc::Sender<LogEvent>) -> anyhow::Result<()> {\n    let (done_tx, done_rx) = std::sync::mpsc::channel();\n    tx.send(LogEvent::Sync(done_tx))\n        .map_err(|e| anyhow::anyhow!(\"failed to request logging sync: {e}\"))?;\n\n    done_rx\n        .recv()\n        .map_err(|e| anyhow::anyhow!(\"failed to receive logging sync acknowledgement: {e}\"))?\n}\n\n/// Logs a message with the given level, color, and component.","sourceCodeStart":1286,"sourceCodeEnd":1322,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/logging/logger.rs#L1286-L1322","documentation":"The flush-to-disk routine only runs while the logger lifecycle is Running and requires the global LOGGER_TX sender to be present. If the lifecycle says Running but the sender slot was never populated (or was consumed), the internal invariant is broken and this error is raised instead of silently skipping the flush.","triggerScenarios":"Calling the flush/sync-to-disk method while LOGGER_TX.get() returns None even though lifecycle == Running — e.g. after a corrupted or partial initialization sequence.","commonSituations":"Custom or embedded integration that manipulated the logger lifecycle directly, a race between init and an early flush call, or library misuse of internal logging APIs.","solutions":["Verify logging initialization completed fully (including sender publication) before calling flush.","Check that no code path sets lifecycle to Running without publishing LOGGER_TX — this indicates an internal bug; report/reproduce with init logs.","Reinitialize logging cleanly at process start and only call flush after successful init.","As a defensive measure, treat flush errors as non-fatal in application shutdown handlers, but fix the underlying init ordering."],"exampleFix":"// before\nlogging_init(cfg).ok(); // ignore init failure\nlogging_flush()?; // bails: no sender\n// after\nlogging_init(cfg)?; // propagate init errors\nlogging_flush()?;","handlingStrategy":"try-catch","validationCode":"fn flush_safe() -> anyhow::Result<()> {\n    // only flush after a confirmed successful init\n    logging_flush()\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = logging_flush() {\n    if e.to_string().contains(\"without a published sender\") {\n        eprintln!(\"flush skipped: logger not fully initialized\");\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["Only call flush after logging_init returned Ok.","Never manipulate logger lifecycle internals directly.","Log or record init failures instead of ignoring them."],"tags":["logging","internal-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-14T00:17:10.932Z"}