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
- Verify the app can create a file in the log directory (touch GitButler.test.log); fix permissions or add AV exclusions
- If you changed log_prefix/log_suffix, keep them free of path separators and keep max_log_files >= 1
- Point logging at a known-writable directory via E2E_TEST_APP_DATA_DIR to separate environment from code issues
- 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
- Keep filename prefix/suffix free of path separators and max_log_files >= 1 when customizing
- Recreate the log directory if external cleanup may remove it between checks
- Propagate the appender error so the OS-level cause (permissions, lock) is visible
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
- failed to create logs dir
- failed to set subscriber
- product name not set
- failed to create config dir
- missing config dir
AI-assisted analysis of gitbutlerapp/gitbutler@caf1f223d3 (2026-08-20).
Data as JSON: /api/errors/8727c3622ea303bb.
Report an issue: GitHub.