gitbutlerapp/gitbutler · error

broker has not been configured

Error message

broker has not been configured

What it means

`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.

Source

Thrown at crates/but-askpass/src/lib.rs:83

/// This function should be called **exactly once** during startup if the custom askpass broker
/// should **not** be used (currently the sensible approach for CLI). Otherwise, call [`init`] at
/// startup instead.
pub fn disable() {
    GLOBAL_ASKPASS_BROKER
        .set(None)
        .unwrap_or_else(|_| panic!("broker already configured"))
}

/// Get the global askpass broker, assuming it's configured.
///
/// # Panics
/// Panics if neither [`init`] nor [`disable`] has been called. This is an important property as we
/// use the state of the broker to determine whether to use our askpass overrides or not. If it's
/// not explicitly set, there is no way to tell the intent and bugs may hide in unexpected places
/// as a consequence. For example, if not initialized for the GUI, the prompt may show up in the
/// terminal that started the GUI.
pub fn get_broker() -> Option<AskpassBroker> {
    try_get_broker().unwrap_or_else(|| panic!("broker has not been configured"))
}

/// Fallibly get the global askpass broker state.
///
/// Returns `None` if neither [`init`], [`try_init`], nor [`disable`] has configured the broker.
pub fn try_get_broker() -> Option<Option<AskpassBroker>> {
    GLOBAL_ASKPASS_BROKER.get().cloned()
}

struct AskpassRequest {
    sender: oneshot::Sender<Option<String>>,
}

/// An ID for an askpass request.
pub type AskpassRequestId = but_core::Id<'A'>;

/// Additional context sent alongside a credential prompt.
#[derive(Debug, Clone, Serialize)]

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Call `disable()` once at CLI startup, or `init()`/`try_init()` for GUI functionality, before any git network operation.
  2. Switch probing code to `try_get_broker()`, which distinguishes 'not configured' from 'configured as disabled'.
  3. If hit in tests, add the startup call to the test harness setup.

Example fix

// before
let broker = but_askpass::get_broker(); // panics if never configured

// after
match but_askpass::try_get_broker() {
    Some(broker) => { /* configured (or None = disabled) */ }
    None => { /* run startup init()/disable() first */ }
}
Defensive patterns

Strategy: validation

Validate before calling

match but_askpass::try_get_broker() {
    Some(_) => {
        // init() or disable() already ran; get_broker() is safe
        let _broker = but_askpass::get_broker();
    }
    None => {
        // not configured yet: run init()/disable() before any git network operation
        but_askpass::disable();
    }
}

Type guard

fn broker_ready() -> bool {
    // Some(_) means init() or disable() ran; None means get_broker() would panic
    but_askpass::try_get_broker().is_some()
}

Try / catch

let broker = std::panic::catch_unwind(std::panic::AssertUnwindSafe(but_askpass::get_broker))
    .unwrap_or_else(|_| panic!("askpass broker used before init()/disable() — add startup setup"));

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20). Data as JSON: /api/errors/7196d3d5cd0d0235. Report an issue: GitHub.