gitbutlerapp/gitbutler · error

product name not set

Error message

product name not set

What it means

get_server_addr() picks the devtools/tokio-console port (6667/6668/6669) by comparing app_handle.config().product_name against known names. Tauri's productName config field is optional; when the running app's Tauri context has no productName, config.product_name is None and expect("product name not set") panics inside logs::init.

Source

Thrown at crates/gitbutler-tauri/src/logs.rs:113

/// It is pretty much the same as `LevelFilter` in debug builds.
fn should_log(level: Option<Level>, meta: &tracing::Metadata<'_>) -> bool {
    let Some(level) = level else {
        return false;
    };
    if *meta.level() > level {
        return false;
    }
    if level > Level::DEBUG {
        return true;
    }
    meta.module_path().is_none_or(|p| {
        p.starts_with("gitbutler_") || p.starts_with("but::") || p.starts_with("but_")
    })
}

fn get_server_addr(app_handle: &AppHandle) -> (Ipv4Addr, u16) {
    let config = app_handle.config();
    let product_name = config.product_name.as_ref().expect("product name not set");
    let port = if product_name.eq("GitButler") {
        6667
    } else if product_name.eq("GitButler Nightly") {
        6668
    } else {
        6669
    };
    (Ipv4Addr::LOCALHOST, port)
}

/// Originally based on https://github.com/tokio-rs/tracing/blob/44861cad7a821f08b3c13aba14bb8ddf562b7053/tracing-appender/src/rolling.rs#L571
#[instrument(err(Debug))]
fn prune_old_logs(
    log_directory: &Path,
    log_filename_prefix: Option<&str>,
    log_filename_suffix: Option<&str>,
    max_files: usize,
) -> anyhow::Result<()> {

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Set productName in the Tauri config ("GitButler", "GitButler Nightly", "GitButler Test", or your fork's name)
  2. If the field is legitimately optional in your build, default it instead of expecting (see exampleFix)
  3. Debug-print app_handle.config().product_name at startup to confirm what the running context actually contains

Example fix

// before
let product_name = config.product_name.as_ref().expect("product name not set");

// after
let product_name = config.product_name.as_deref().unwrap_or("GitButler");
Defensive patterns

Strategy: validation

Validate before calling

// Before startup, confirm the packaged config carries productName
let cfg: tauri_utils::config::Config = serde_json::from_str(include_str!("../tauri.conf.json"))?;
assert!(cfg.product_name.is_some(), "productName missing in tauri.conf.json");

Type guard

fn has_product_name(app: &tauri::AppHandle) -> bool {
    app.config().product_name.is_some()
}

Prevention

When it happens

Trigger: Any startup path reaching get_server_addr (performance/tokio-console logging setup) in a build whose Tauri configuration lacks productName: custom forks trimming tauri.conf.json, test apps, or contexts generated without the field.

Common situations: Forking the desktop app and slimming tauri.conf.json, E2E/test builds using a different config, or Tauri version upgrades that move/rename the productName field.

Related errors


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