gitbutlerapp/gitbutler · critical

missing config dir

Error message

missing config dir

What it means

gitbutler-tauri's main() resolves the settings directory with but_path::app_config_dir().expect("missing config dir"). app_config_dir() wraps dirs::config_dir(), which returns None when the platform's config location cannot be determined: on Linux when $HOME is unset/empty or $XDG_CONFIG_HOME is set to a relative path, on macOS when no home directory exists, on Windows when the known-folder lookup fails. The expect converts that environment problem into an immediate startup panic; setting E2E_TEST_APP_DATA_DIR bypasses dirs::config_dir() entirely (but-path/src/lib.rs:93-100).

Source

Thrown at crates/gitbutler-tauri/src/main.rs:53

            but_askpass::disable();
            return runtime.block_on(but::handle_args(std::env::args_os()));
        }
    }
    let performance_logging = std::env::var_os("GITBUTLER_PERFORMANCE_LOG").is_some();
    let tauri_debug_logging = std::env::var_os("GITBUTLER_TAURI_DEBUG_LOG").is_some();

    let mut tauri_context = generate_context!();
    but_secret::secret::set_application_namespace(&tauri_context.config().identifier);

    // Set the macOS notification bundle ID so notifications appear as GitButler.
    #[cfg(target_os = "macos")]
    {
        if let Err(e) = notify_rust::set_application(&tauri_context.config().identifier) {
            tracing::warn!(error = %e, "Failed to set notification application");
        }
    }

    let config_dir = but_path::app_config_dir().expect("missing config dir");
    std::fs::create_dir_all(&config_dir).expect("failed to create config dir");
    let custom_settings = cfg!(feature = "packaged-but-distribution")
        .then(but_settings::customization::packaged_but_binary);
    // While it serves a function, this behavior is sub-optimal. The proper solution is to decouple:
    // - Checking for updates from
    // - Performing an update
    // This way people can be informed that there is an update even if self-updating is not possible (i.e. installed via package manager).
    let custom_settings = if cfg!(feature = "disable-auto-updates") {
        but_settings::customization::merge_two(
            but_settings::customization::disable_auto_update_checks(),
            custom_settings,
        )
        .into()
    } else {
        custom_settings
    };
    let mut app_settings =
        AppSettingsWithDiskSync::new_with_customization(config_dir.clone(), custom_settings)

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Launch the app with a valid HOME (export HOME=/home/<user>)
  2. Make XDG_CONFIG_HOME an absolute path or unset it so the default ~/.config is used
  3. For automated runs, set E2E_TEST_APP_DATA_DIR to a writable directory - it overrides the lookup
  4. As a contributor: replace the expect with ? so main() reports the failure cleanly (see exampleFix)

Example fix

// before
let config_dir = but_path::app_config_dir().expect("missing config dir");

// after
let config_dir = but_path::app_config_dir()
    .context("could not resolve config dir (is $HOME set and absolute?)")?;
Defensive patterns

Strategy: validation

Validate before calling

// Environment pre-check mirroring dirs::config_dir() requirements
fn config_dir_resolvable() -> bool {
    if std::env::var_os("E2E_TEST_APP_DATA_DIR").is_some() {
        return true;
    }
    #[cfg(target_os = "linux")]
    {
        let home_ok = std::env::var_os("HOME").is_some_and(|h| !h.is_empty());
        let xdg_ok = std::env::var_os("XDG_CONFIG_HOME")
            .map(|v| std::path::Path::new(&v).is_absolute())
            .unwrap_or(true);
        home_ok && xdg_ok
    }
    #[cfg(not(target_os = "linux"))]
    { true }
}

Prevention

When it happens

Trigger: Launching the desktop app from an environment without a resolvable config directory: HOME unset or empty (services, daemons, minimal containers, some CI runners), a relative XDG_CONFIG_HOME on Linux, or a broken user profile.

Common situations: Running the app from systemd/launchd/cron without a full user environment, inside minimal Docker images, after HOME was cleared, or with misconfigured XDG variables.

Related errors


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