atuinsh/atuin · warning

Could not build config

Error message

Could not build config

What it means

`Settings::utc()` calls `.build()` on the config and `.expect("Could not build config")` panics if building the merged configuration fails. This merges defaults with overrides; failure means the in-memory configuration is structurally inconsistent. Like the other expects in this constructor, it marks an "impossible" internal invariant: default settings must always build.

Solutions

  1. Check for a version mismatch between atuin-client and the `config` crate; align versions.
  2. Inspect the `timezone` field type in Settings — if it changed from string/offset-compatible to a stricter type, the "0" override may no longer coerce.
  3. Pin to a known-good atuin-client release where `utc()` works.
  4. File an upstream issue with the panic backtrace; this is an internal invariant failure.
Defensive patterns

Strategy: try-catch

Try / catch

// This is an expect() panic, not a returned error — cannot be matched on.
// Isolate via catch_unwind when calling library defaults in untrusted embedding contexts:
let settings = std::panic::catch_unwind(Settings::default)
    .map_err(|_| anyhow::anyhow!("default settings failed to build; check dependency versions"))?;

Prevention

When it happens

Trigger: Calling `Settings::utc()` when `Config::build` fails — e.g. a type mismatch between the default value and the "timezone" "0" string override introduced by a Settings field type change (deserialization happens later, but build-time coercion of typed values can fail).

Common situations: After upgrading atuin-client or the `config` crate where defaults/field types changed so the default+override merge no longer coerces; effectively an upstream regression, not user error.

Related errors


AI-assisted analysis of atuinsh/atuin@900007c480 (2026-09-19). Data as JSON: /api/errors/d23971f912f59e35. Report an issue: GitHub.

Appendix: source

Thrown at crates/atuin-client/src/settings.rs:1158

    #[serde(default)]
    pub logs: Logs,

    #[serde(default)]
    pub meta: meta::Settings,

    #[serde(default)]
    pub ai: Ai,
}

impl Settings {
    #[must_use]
    pub fn utc() -> Self {
        Self::builder()
            .expect("Could not build default")
            .set_override("timezone", "0")
            .expect("failed to override timezone with UTC")
            .build()
            .expect("Could not build config")
            .try_deserialize()
            .expect("Could not deserialize config")
    }

    #[must_use]
    pub fn search_mode(&self) -> SearchMode {
        self.requested_search_mode.into()
    }

    pub fn search_mode_shell_up_key_binding(&self) -> Option<SearchMode> {
        self.requested_search_mode_shell_up_key_binding.map(Into::into)
    }

    /// Return the active search mode depending on whether Atuin was invoked from the "up"
    /// keybinding.
    ///
    /// If Atuin was invoked from the "up" keybinding, this returns
    /// [`Self::search_mode_shell_up_key_binding`], falling back to [`Self::search_mode`] if that

View on GitHub (pinned to 900007c480)