{"record":{"id":"8727c3622ea303bb","repo":"gitbutlerapp/gitbutler","slug":"initializing-rolling-file-appender-failed","errorCode":null,"errorMessage":"initializing rolling file appender failed","messagePattern":"initializing rolling file appender failed","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/gitbutler-tauri/src/logs.rs","lineNumber":26,"sourceCode":"pub fn init(\n    app_handle: &AppHandle,\n    logs_dir: &Path,\n    performance_logging: bool,\n    enable_tokio_console_log: bool,\n) {\n    fs::create_dir_all(logs_dir).expect(\"failed to create logs dir\");\n\n    let log_prefix = \"GitButler\";\n    let log_suffix = \"log\";\n    let max_log_files = 14;\n    remove_old_logs(logs_dir).ok();\n    let file_appender = RollingFileAppender::builder()\n        .rotation(Rotation::DAILY)\n        .max_log_files(max_log_files)\n        .filename_prefix(log_prefix)\n        .filename_suffix(log_suffix)\n        .build(logs_dir)\n        .expect(\"initializing rolling file appender failed\");\n    let (file_writer, guard) = tracing_appender::non_blocking(file_appender);\n    // As the file-writer only checks `max_log_files` on file rotation, it basically never happens.\n    // Run it now.\n    prune_old_logs(logs_dir, Some(log_prefix), Some(log_suffix), max_log_files).ok();\n\n    app_handle.manage(guard); // keep the guard alive for the lifetime of the app\n\n    let format_for_humans = tracing_subscriber::fmt::format()\n        .with_file(true)\n        .with_line_number(true)\n        .with_target(false)\n        .compact();\n\n    let log_level_filter = std::env::var(\"LOG_LEVEL\")\n        .unwrap_or(\"info\".to_string())\n        .to_lowercase()\n        .parse()\n        .unwrap_or(LevelFilter::INFO);","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/gitbutlerapp/gitbutler/blob/caf1f223d3cfb94488c9198ad34487c6006c648f/crates/gitbutler-tauri/src/logs.rs#L8-L44","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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)"],"exampleFix":"// before\n.build(logs_dir).expect(\"initializing rolling file appender failed\");\n\n// after\n.build(logs_dir)\n    .with_context(|| format!(\"initializing rolling file appender in {} failed\", logs_dir.display()))?;","handlingStrategy":"validation","validationCode":"// Prove a log file can be created in the directory before init\nfn log_dir_writable(dir: &std::path::Path) -> bool {\n    let probe = dir.join(\".write-probe\");\n    std::fs::write(&probe, b\"\").is_ok() && std::fs::remove_file(&probe).is_ok()\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["tauri","tracing","logging","appender","permissions","startup","panic"],"backgroundTag":"log-appender-init-failed","analyzedSha":"caf1f223d3cfb94488c9198ad34487c6006c648f","analyzedAt":"2026-08-20T07:55:40.983Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}