{"record":{"id":"7196d3d5cd0d0235","repo":"gitbutlerapp/gitbutler","slug":"broker-has-not-been-configured","errorCode":null,"errorMessage":"broker has not been configured","messagePattern":"broker has not been configured","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/but-askpass/src/lib.rs","lineNumber":83,"sourceCode":"/// This function should be called **exactly once** during startup if the custom askpass broker\n/// should **not** be used (currently the sensible approach for CLI). Otherwise, call [`init`] at\n/// startup instead.\npub fn disable() {\n    GLOBAL_ASKPASS_BROKER\n        .set(None)\n        .unwrap_or_else(|_| panic!(\"broker already configured\"))\n}\n\n/// Get the global askpass broker, assuming it's configured.\n///\n/// # Panics\n/// Panics if neither [`init`] nor [`disable`] has been called. This is an important property as we\n/// use the state of the broker to determine whether to use our askpass overrides or not. If it's\n/// not explicitly set, there is no way to tell the intent and bugs may hide in unexpected places\n/// as a consequence. For example, if not initialized for the GUI, the prompt may show up in the\n/// terminal that started the GUI.\npub fn get_broker() -> Option<AskpassBroker> {\n    try_get_broker().unwrap_or_else(|| panic!(\"broker has not been configured\"))\n}\n\n/// Fallibly get the global askpass broker state.\n///\n/// Returns `None` if neither [`init`], [`try_init`], nor [`disable`] has configured the broker.\npub fn try_get_broker() -> Option<Option<AskpassBroker>> {\n    GLOBAL_ASKPASS_BROKER.get().cloned()\n}\n\nstruct AskpassRequest {\n    sender: oneshot::Sender<Option<String>>,\n}\n\n/// An ID for an askpass request.\npub type AskpassRequestId = but_core::Id<'A'>;\n\n/// Additional context sent alongside a credential prompt.\n#[derive(Debug, Clone, Serialize)]","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/but-askpass/src/lib.rs#L65-L101","documentation":"`get_broker()` (lib.rs:83) panics when the global `OnceLock<Option<AskpassBroker>>` was never set by `init()`, `try_init()`, or `disable()`. The panic is intentional: the broker's state decides whether GitButler's askpass overrides are used, and an unset broker would let credential prompts silently leak to the terminal that started the GUI. `try_get_broker()` returns `Option<Option<AskpassBroker>>` and is the non-panicking probe.","triggerScenarios":"Calling `but_askpass::get_broker()` in a binary that never ran `init()`/`try_init()`/`disable()` at startup; linking but-askpass into a new test binary or N-API host without the one-time setup call; code that runs before main-level initialization.","commonSituations":"New host application wired to the but-* crates with missing startup boilerplate; unit tests exercising askpass paths without the global setup; race where a background thread calls `get_broker()` before startup completes.","solutions":["Call `disable()` once at CLI startup, or `init()`/`try_init()` for GUI functionality, before any git network operation.","Switch probing code to `try_get_broker()`, which distinguishes 'not configured' from 'configured as disabled'.","If hit in tests, add the startup call to the test harness setup."],"exampleFix":"// before\nlet broker = but_askpass::get_broker(); // panics if never configured\n\n// after\nmatch but_askpass::try_get_broker() {\n    Some(broker) => { /* configured (or None = disabled) */ }\n    None => { /* run startup init()/disable() first */ }\n}","handlingStrategy":"validation","validationCode":"match but_askpass::try_get_broker() {\n    Some(_) => {\n        // init() or disable() already ran; get_broker() is safe\n        let _broker = but_askpass::get_broker();\n    }\n    None => {\n        // not configured yet: run init()/disable() before any git network operation\n        but_askpass::disable();\n    }\n}","typeGuard":"fn broker_ready() -> bool {\n    // Some(_) means init() or disable() ran; None means get_broker() would panic\n    but_askpass::try_get_broker().is_some()\n}","tryCatchPattern":"let broker = std::panic::catch_unwind(std::panic::AssertUnwindSafe(but_askpass::get_broker))\n    .unwrap_or_else(|_| panic!(\"askpass broker used before init()/disable() — add startup setup\"));","preventionTips":["Make broker setup the first GitButler call in main()/entrypoint, before spawning threads that do git I/O.","Use try_get_broker() in defensive or test code instead of get_broker().","grep new binaries/tests for get_broker() and confirm each has a preceding setup call."],"tags":["rust","askpass","initialization-order","panic","credentials"],"backgroundTag":"missing-initialization","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}