gitbutlerapp/gitbutler · error

Could not read settings: {e:?}

Error message

Could not read settings: {e:?}

What it means

The settings watcher's RwLock read failed, which in Rust means the lock is poisoned: some thread panicked while holding the write lock on the AppSettings snapshot. Every later get() then reports this wrapper error instead of settings.

Source

Thrown at crates/but-settings/src/watch.rs:96

        config_dir: impl AsRef<Path>,
        customization: Option<serde_json::Value>,
    ) -> Result<Self> {
        let config_path = config_dir.as_ref().join(SETTINGS_FILE);
        let app_settings = AppSettings::load(&config_path, customization.clone())?;
        let app_settings = Arc::new(RwLock::new(app_settings));

        Ok(Self {
            config_path,
            snapshot: app_settings,
            customization,
        })
    }

    /// Return a reference to the most recently loaded [`AppSettings`].
    pub fn get(&self) -> Result<RwLockReadGuard<'_, AppSettings>> {
        self.snapshot
            .read()
            .map_err(|e| anyhow::anyhow!("Could not read settings: {e:?}"))
    }

    /// Allow changes only from within this crate to implement all possible settings updates [here](crate::api).
    pub(crate) fn get_mut_enforce_save(&self) -> Result<AppSettingsEnforceSaveToDisk<'_>> {
        self.snapshot
            .write()
            .map(|snapshot| AppSettingsEnforceSaveToDisk {
                snapshot,
                config_path: &self.config_path,
                saved: false,
                customization: self.customization.clone(),
            })
            .map_err(|e| anyhow::anyhow!("Could not write settings: {e:?}"))
    }

    /// The path from which application settings will be read from disk.
    pub fn config_path(&self) -> &Path {
        &self.config_path

View on GitHub (pinned to caf1f223d3)

Solutions

  1. Search the log for the FIRST panic before this error — the panic is the root cause, this error is fallout
  2. Fix or handle the panic in the settings-mutation path (often a disk I/O unwrap or serialization panic)
  3. Restart the application to clear the poisoned lock after fixing or working around the root panic
  4. If writing new settings code, never unwrap inside get_mut_enforce_save's guard scope
Defensive patterns

Strategy: try-catch

Try / catch

match watcher.get() {
    Ok(settings) => { /* use settings */ }
    Err(e) if e.to_string().contains("Could not read settings") => {
        // lock poisoned — restart-worthy state; fall back to defaults if acceptable
        AppSettings::default()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling AppSettingsWatcher::get() (or any read of the settings snapshot) after a panic occurred inside get_mut_enforce_save or a settings-mutation code path that held the write lock across the panic.

Common situations: A bug in a settings-save routine panics once; from then on every settings read in the process fails with this error until restart. Typically seen in logs as a cascade right after an unrelated panic message.

Related errors


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