gitbutlerapp/gitbutler · critical
tauri event emission doesn't fail in practice
Error message
tauri event emission doesn't fail in practice
What it means
Tauri's `AppHandle::emit` broadcasts an event (here "git_prompt", carrying a git credential prompt collected by but_askpass) to all webview listeners and returns a `Result`. It fails when the payload cannot be serialized, when the internal event manager or channel is shut down (typically during app teardown), or when no live listener target exists. The `.expect` converts that rare failure into a panic inside the askpass callback, which takes down the whole desktop app the next time git asks for credentials.
Source
Thrown at crates/gitbutler-tauri/src/main.rs:151
inherit_interactive_login_shell_environment_if_not_launched_from_terminal();
migrate_projects().ok();
tracing::info!(
"system git executable for fetch/push: {git:?}",
git = gix::path::env::exe_invocation(),
);
if cfg!(windows) {
tracing::info!("system git bash: {bash:?}", bash = gix::path::env::shell());
} else {
tracing::info!("SHELL env: {var:?}", var = std::env::var_os("SHELL"));
}
but_askpass::init({
let handle = app_handle.clone();
move |event| {
handle
.emit("git_prompt", event)
.expect("tauri event emission doesn't fail in practice")
}
});
tracing::info!(version = %app_handle.package_info().version,
name = %app_handle.package_info().name, "starting app");
app_handle.manage(WindowState::new(app_handle.clone()));
app_settings.watch_in_background({
let app_handle = app_handle.clone();
move |app_settings| {
gitbutler_tauri::ChangeForFrontend::from(app_settings).send(&app_handle)
}
})?;
let archival = but_feedback::Archival {
cache_dir: app_cache_dir.clone(),View on GitHub (pinned to caf1f223d3)
Solutions
- Replace the .expect with a logged non-fatal branch (tracing::warn) so an emit failure can never crash the app
- If the frontend must answer the prompt, make the askpass request fail so git aborts instead of hanging without an answer
- Guard the shutdown race: skip emitting or ignore emit errors once the app is exiting
- Add a test asserting the git_prompt payload is Serialize and matches the frontend's expected shape
Example fix
// before
but_askpass::init({
let handle = app_handle.clone();
move |event| {
handle
.emit("git_prompt", event)
.expect("tauri event emission doesn't fail in practice")
}
});
// after
but_askpass::init({
let handle = app_handle.clone();
move |event| {
if let Err(err) = handle.emit("git_prompt", event) {
tracing::warn!("failed to emit git_prompt event: {err}");
}
}
}); Defensive patterns
Strategy: try-catch
Validate before calling
// Rust: confirm a listener target still exists before emitting
if handle.webview_windows().is_empty() {
tracing::debug!("no windows; skipping git_prompt emit");
return;
} Try / catch
move |event| {
if let Err(err) = handle.emit("git_prompt", event) {
tracing::warn!("git_prompt emit failed: {err}");
// fail the askpass request so git does not block awaiting an answer
}
} Prevention
- Never use .expect on Result-returning event APIs inside long-lived callbacks
- Keep event payloads plain serde types covered by tests
- Make the askpass flow fail gracefully during shutdown instead of panicking
When it happens
Trigger: A git operation over HTTPS without a cached credential fires the but_askpass::init callback at crates/gitbutler-tauri/src/main.rs:151, and `handle.emit("git_prompt", event)` returns Err — e.g. the payload type no longer implements Serialize after a refactor, the event manager is shut down while the app is quitting, or the webview was already destroyed.
Common situations: App shutdown racing an in-flight credential prompt; a Tauri major-version upgrade changing emit or event-manager semantics; a payload struct edited without keeping Serialize; emitting after the last window closed.
Related errors
- broker already configured
- broker has not been configured
- askpass broker must be initialized
- Failed to build tauri app
- BUG: {id} is queued
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/a913effc12bebdd3.
Report an issue: GitHub.