{"record":{"id":"37e607a799a4213b","repo":"gitbutlerapp/gitbutler","slug":"theme-may-only-be-initialized-once","errorCode":null,"errorMessage":"theme may only be initialized once","messagePattern":"theme may only be initialized once","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but/src/theme.rs","lineNumber":69,"sourceCode":"\nconst MONOKAI_THEME_LIGHT: &[u8] =\n    include_bytes!(\"../assets/syntax-highlighting-themes/Monokai Extended Light.tmTheme\");\n\n/// The minimum number of change ID characters displayed for a commit, so that\n/// short IDs remain visually distinctive.\npub(crate) const MIN_DISPLAYED_CHANGE_ID_CHARS: usize = 3;\n\n/// Global theme instance, initialized once at startup.\nstatic THEME: OnceLock<Theme> = OnceLock::new();\n\n/// Initialize the global theme.\n///\n/// Must be called exactly once, before any call to [`get`].\n/// Panics if called more than once.\npub fn init(theme: Theme) {\n    THEME\n        .set(theme)\n        .expect(\"theme may only be initialized once\");\n}\n\n/// Return a reference to the global theme.\n///\n/// Panics if [`init`] has not been called yet.\npub fn get() -> &'static Theme {\n    #[cfg(test)]\n    {\n        THEME.get_or_init(Theme::default)\n    }\n    #[cfg(not(test))]\n    {\n        THEME\n            .get()\n            .expect(\"theme::init() must be called before getting the theme\")\n    }\n}\n","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/2497b8007aa4a1922dae9a805b32ffe5b5037785/crates/but/src/theme.rs#L51-L87","documentation":"The global TUI theme lives in a static OnceLock<Theme>; theme::init(theme) must run exactly once per process before anything reads it, and a second init call panics here. The real CLI inits once at startup, so this panic is almost always a same-process re-entry issue: test harnesses that run several but entry points in one process, or an embedded host (daemon/MCP-style) that re-initializes per session.","triggerScenarios":"Calling theme::init twice within one process: integration tests that invoke TUI commands repeatedly without process isolation; a library embedding that calls init per command; wrapping entry points in a loop in a long-lived host.","commonSituations":"Rust test suites where multiple tests each bootstrap the theme in the same process; plugin/embedding code around but crates; refactoring main() so init moved into a per-invocation helper.","solutions":["Initialize the theme once at process start, not per operation; move init into the single entry bootstrap","In callers that may repeat, guard with std::sync::Once (see validationCode) so init runs at most once per process","Expose/depend on a try_init(theme) -> bool (THEME.set(theme).is_ok()) and use it where repeated init is possible","In tests, rely on theme::get()'s cfg(test) defaulting (get_or_init(Theme::default)) instead of calling init"],"exampleFix":"// before — second call in the same process panics\ntheme::init(theme);\n\n// after — idempotent guard at the call site (or make init itself try-init)\nstatic THEME_INIT: std::sync::Once = std::sync::Once::new();\nTHEME_INIT.call_once(|| theme::init(theme));","handlingStrategy":"validation","validationCode":"// idempotent bootstrap — safe to call from tests/embeddings repeatedly\nstatic THEME_INIT: std::sync::Once = std::sync::Once::new();\nTHEME_INIT.call_once(|| {\n    theme::init(theme::load(theme_path).unwrap_or_default());\n});","typeGuard":null,"tryCatchPattern":"// detect double-init without dying: keep the existing theme if already set\nlet _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| theme::init(theme)));","preventionTips":["Call theme::init exactly once, at process start — never per command, request, or test iteration","In test harnesses, prefer theme::get()'s cfg(test) default over calling init at all","If embedding but entry points in one process, isolate them per process (as the real CLI does) or guard with Once"],"tags":["rust","global-state","oncelock","double-init","theme","tests"],"backgroundTag":"global-state-double-initialization","analyzedSha":"2497b8007aa4a1922dae9a805b32ffe5b5037785","analyzedAt":"2026-08-17T00:30:25.648Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}