{"record":{"id":"b4b240416bc240f2","repo":"gitbutlerapp/gitbutler","slug":"broker-already-configured","errorCode":null,"errorMessage":"broker already configured","messagePattern":"broker already configured","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/but-askpass/src/lib.rs","lineNumber":35,"sourceCode":"    error::Error,\n    fmt,\n    sync::{Arc, OnceLock},\n};\n\nuse but_core::ref_metadata::StackId;\nuse serde::Serialize;\nuse tokio::sync::{Mutex, oneshot};\n\nstatic GLOBAL_ASKPASS_BROKER: OnceLock<Option<AskpassBroker>> = OnceLock::new();\n\n/// Initialize the global askpass broker.\n///\n/// # Panics\n/// This function should be called **exactly once** during startup if the custom askpass broker\n/// needs to be used (currently only needed for GUI functionality). Otherwise, call [`disable`] at\n/// startup instead.\npub fn init(submit_prompt: impl Fn(PromptEvent<Context>) + Send + Sync + 'static) {\n    try_init(submit_prompt).unwrap_or_else(|_| panic!(\"broker already configured\"));\n}\n\n/// The askpass broker has already been explicitly initialized or disabled.\n#[derive(Debug, Clone, Copy)]\npub struct BrokerAlreadyConfigured;\n\nimpl fmt::Display for BrokerAlreadyConfigured {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        f.write_str(\"broker already configured\")\n    }\n}\n\nimpl Error for BrokerAlreadyConfigured {}\n\n/// Fallibly initialize the global askpass broker.\n///\n/// This is useful for runtime bindings that need to report startup errors to their host instead of\n/// panicking across an FFI boundary.","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-askpass/src/lib.rs#L17-L53","documentation":"init() is a thin wrapper over try_init() that panics with 'broker already configured' when GLOBAL_ASKPASS_BROKER (a OnceLock) was already set. The crate's contract is that startup configures askpass exactly once — init() for the GUI, disable() for the CLI — so a second init, or init after disable, is a programming error that aborts the process.","triggerScenarios":"Calling but_askpass::init() twice in one process; calling init() after disable() already ran; test binaries that initialize the broker per test inside a shared process.","commonSituations":"A new startup path added a second init call alongside the existing one; embedding code calls both disable() (sensible for CLI) and init(); integration tests reusing the process where the OnceLock retains the first configuration.","solutions":["Use the fallible try_init() (or check try_get_broker().is_none() first) and log instead of panicking when already configured.","Audit startup paths so exactly one of init()/disable() runs per process.","In tests, run each case in its own process or branch on try_get_broker() to avoid re-initialization."],"exampleFix":"// before\nbut_askpass::init(submit_prompt); // panics: broker already configured\n\n// after\nif but_askpass::try_init(submit_prompt).is_err() {\n    tracing::warn!(\"askpass broker already configured; skipping re-init\");\n}","handlingStrategy":"validation","validationCode":"// Rust: configure exactly once, fallibly\nif but_askpass::try_get_broker().is_none() {\n    let _ = but_askpass::try_init(submit_prompt);\n}","typeGuard":null,"tryCatchPattern":"// Rust: prefer the fallible API at startup boundaries (especially across FFI)\nif let Err(err) = but_askpass::try_init(submit_prompt) {\n    tracing::warn!(%err, \"askpass broker already configured; continuing with existing broker\");\n}","preventionTips":["Call exactly one of init()/disable() per process, from a single startup path.","Prefer try_init() wherever a repeat call is plausible (FFI hosts, tests).","In test binaries, run each broker-dependent case in its own process since the OnceLock never resets."],"tags":["rust","askpass","panic","once-initialization","startup"],"backgroundTag":"double-initialization-panic","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}