gitbutlerapp/gitbutler · critical
failed to create app settings
Error message
failed to create app settings
What it means
Startup panic in but-server: AppSettingsWithDiskSync::new_with_customization could not load or create the app settings under the configured config directory. Because this is an expect on server boot, any underlying failure - a corrupt settings file, an unwritable or missing config dir, a path occupied by a file, or a full disk - aborts the whole process before it serves anything.
Source
Thrown at crates/but-server/src/lib.rs:381
is_localhost_origin(origin.as_bytes())
}))
.allow_headers(allowed_headers)
.allow_credentials(true);
let config_dir = but_path::app_config_dir().unwrap();
let app_data_dir = but_path::app_data_dir().unwrap();
let broadcaster = Arc::new(Mutex::new(Broadcaster::new()));
let archival = Arc::new(but_feedback::Archival {
cache_dir: app_data_dir.join("cache").clone(),
logs_dir: app_data_dir.join("logs").clone(),
});
let extra = Extra {
active_projects: Arc::new(Mutex::new(ActiveProjects::new())),
archival,
};
let app_settings = AppSettingsWithDiskSync::new_with_customization(config_dir.clone(), None)
.expect("failed to create app settings");
// If a project path was provided, auto-activate that project.
if let Some(ref project_path) = config.project_path {
match but_ctx::Context::discover(project_path) {
Ok(mut ctx) => {
but_api::legacy::projects::prepare_project_for_activation(&mut ctx).ok();
let mut active = extra.active_projects.lock().await;
if active
.set_active(&ctx, &broadcaster, app_settings.clone())
.is_err()
{
tracing::warn!("Failed to activate project at {}", project_path.display());
}
}
Err(err) => {
tracing::warn!(
"Could not discover project at {}: {err}",
project_path.display()View on GitHub (pinned to 2497b8007a)
Solutions
- Make sure the config directory exists and is writable by the running user
- Move aside or delete the existing settings file so a fresh one can be created
- Free disk space if writes fail with ENOSPC
- Re-run the binary and read the stderr just above the panic for the underlying io/parse error
Example fix
// before
let app_settings = AppSettingsWithDiskSync::new_with_customization(config_dir.clone(), None)
.expect("failed to create app settings");
// after
let app_settings = AppSettingsWithDiskSync::new_with_customization(config_dir.clone(), None)
.map_err(|e| anyhow::anyhow!("app settings in {}: {e}", config_dir.display()))?; Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight before server boot: the config dir must be writable
let probe = config_dir.join(".write-probe");
std::fs::write(&probe, b"").with_context(|| format!("config dir {} not writable", config_dir.display()))?;
std::fs::remove_file(&probe).ok(); Prevention
- Add a startup healthcheck that validates the config dir (exists, writable, parses) before expect-based code runs
- Keep settings writes atomic (write temp file + rename) so crashes cannot corrupt the file
- In containers, mount the config volume with correct ownership and read-write mode
When it happens
Trigger: Starting the server with a config dir mounted read-only (container volume) or owned by another user; settings JSON corrupted by a partial write or manual edit; config_dir pointing at a regular file; ENOSPC when persisting the initial defaults.
Common situations: Docker/Kubernetes deployments with mismatched volume mounts; a previous crash interrupting a settings write; running as a service user without ownership of the config directory.
Related errors
- panic while executing `{}`: {} panic backtrace unavailable
- valid hex prefix
- object for prefix exists
- 'dot' (graphviz) must be installed on the system
- all help topics have clap command metadata
AI-assisted analysis of gitbutlerapp/gitbutler@2497b8007a (2026-08-17).
Data as JSON: /api/errors/fcfd2d269e893653.
Report an issue: GitHub.