gitbutlerapp/gitbutler · critical

initializing rolling file appender failed

Error message

initializing rolling file appender failed

What it means

Immediately after creating the directory, logs::init() builds a tracing_appender RollingFileAppender (daily rotation, prefix "GitButler", suffix "log", max 14 files) and unwraps with expect("initializing rolling file appender failed"). build() validates builder parameters and opens the first log file, so it fails when the directory vanished between the two calls, the log file cannot be created (permissions, read-only FS), or parameters are invalid (path separators in prefix/suffix, max_log_files == 0).

Source

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

pub fn init(
    app_handle: &AppHandle,
    logs_dir: &Path,
    performance_logging: bool,
    enable_tokio_console_log: bool,
) {
    fs::create_dir_all(logs_dir).expect("failed to create logs dir");

    let log_prefix = "GitButler";
    let log_suffix = "log";
    let max_log_files = 14;
    remove_old_logs(logs_dir).ok();
    let file_appender = RollingFileAppender::builder()
        .rotation(Rotation::DAILY)
        .max_log_files(max_log_files)
        .filename_prefix(log_prefix)
        .filename_suffix(log_suffix)
        .build(logs_dir)
        .expect("initializing rolling file appender failed");
    let (file_writer, guard) = tracing_appender::non_blocking(file_appender);
    // As the file-writer only checks `max_log_files` on file rotation, it basically never happens.
    // Run it now.
    prune_old_logs(logs_dir, Some(log_prefix), Some(log_suffix), max_log_files).ok();

    app_handle.manage(guard); // keep the guard alive for the lifetime of the app

    let format_for_humans = tracing_subscriber::fmt::format()
        .with_file(true)
        .with_line_number(true)
        .with_target(false)
        .compact();

    let log_level_filter = std::env::var("LOG_LEVEL")
        .unwrap_or("info".to_string())
        .to_lowercase()
        .parse()
        .unwrap_or(LevelFilter::INFO);

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Verify the app can create a file in the log directory (touch GitButler.test.log); fix permissions or add AV exclusions
  2. If you changed log_prefix/log_suffix, keep them free of path separators and keep max_log_files >= 1
  3. Point logging at a known-writable directory via E2E_TEST_APP_DATA_DIR to separate environment from code issues
  4. Propagate the builder error instead of expect so startup reports the exact cause (see exampleFix)

Example fix

// before
.build(logs_dir).expect("initializing rolling file appender failed");

// after
.build(logs_dir)
    .with_context(|| format!("initializing rolling file appender in {} failed", logs_dir.display()))?;
Defensive patterns

Strategy: validation

Validate before calling

// Prove a log file can be created in the directory before init
fn log_dir_writable(dir: &std::path::Path) -> bool {
    let probe = dir.join(".write-probe");
    std::fs::write(&probe, b"").is_ok() && std::fs::remove_file(&probe).is_ok()
}

Prevention

When it happens

Trigger: Desktop app startup where GitButler.<date>.log cannot be created inside the log dir: permission denied or file locked by antivirus/backup, directory removed concurrently, or local forks that changed log_prefix/log_suffix/max_log_files to invalid values.

Common situations: Antivirus or backup tools locking freshly created log files on Windows, sandboxed environments, and forks customizing the logging constants without respecting the builder's validation rules.

Related errors


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