atuinsh/atuin · error · std::io::Error

Failed to deserialize theme

Error message

Failed to deserialize theme: {}

What it means

The theme file was found and read, but its contents could not be deserialized into a ThemeConfig. The error wraps the underlying deserializer message; when debug mode is off, the detailed reason is replaced with a generic hint, so enable debug to see the real cause.

Solutions

  1. Enable debug mode to surface the underlying deserializer error message, then fix the offending key/type in the theme file.
  2. Validate the theme file's TOML syntax and that every field matches ThemeConfig's expected types (colors: map of meaning -> string; parent: optional string).
  3. Compare against a known-good stock theme file and remove unsupported keys.
  4. Check the theme file version matches your Atuin version.

Example fix

// before: colors = { bg = "#fff" }  // unknown key fails schema
// after:  colors = { background = "#ffffff" }
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-validate the theme file parses as TOML and has expected key types
let raw = std::fs::read_to_string(&path)?;
let toml: toml::Value = raw.parse()?;
if let Some(colors) = toml.get("colors").and_then(|c| c.as_table()) {
    for (k, v) in colors {
        assert!(v.is_str(), "colors.{k} must be a string, got {v}");
    }
}

Type guard

fn is_parsable_theme(raw: &str) -> bool {
    raw.parse::<toml::Value>()
        .ok()
        .and_then(|v| v.get("colors").and_then(|c| c.as_table()).map(|t| {
            t.values().all(|val| val.as_str().is_some())
        }))
        .unwrap_or(false)
}

Try / catch

match theme_engine.load_theme_from_file(name, 3) {
    Ok(t) => apply(t),
    Err(e) if e.to_string().contains("Failed to deserialize theme") => {
        eprintln!("theme '{name}' invalid; check keys/types (run with debug for details)");
        apply(default_theme());
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling load_theme_from_config on a config file whose TOML does not match the ThemeConfig schema — unknown keys (if strict), wrong types for colors/parent, or malformed TOML.

Common situations: Hand-edited theme files with typos, theme files from older/newer Atuin versions with changed schema, copying a theme written for a different tool, or invalid TOML syntax.

Related errors


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

Appendix: source

Thrown at crates/atuin-client/src/theme.rs:430

        config_builder = config_builder
            .add_source(ConfigFile::new(theme_file.to_str().unwrap(), FileFormat::Toml));

        let config = config_builder.build()?;
        self.load_theme_from_config(name, config, max_depth)
    }

    pub fn load_theme_from_config(
        &mut self,
        name: &str,
        config: Config,
        max_depth: u8,
    ) -> Result<&Theme, Box<dyn error::Error>> {
        let debug = self.debug;
        let theme_config: ThemeConfig = match config.try_deserialize() {
            Ok(tc) => tc,
            Err(e) => {
                return Err(Box::new(Error::new(
                    ErrorKind::InvalidInput,
                    format!(
                        "Failed to deserialize theme: {}",
                        if debug {
                            e.to_string()
                        } else {
                            "set theme debug on for more info".to_string()
                        }
                    ),
                )));
            }
        };
        let colors: HashMap<Meaning, String> = theme_config.colors;
        let parent: Option<&Theme> = match theme_config.theme.parent {
            Some(parent_name) => {
                if max_depth == 0 {
                    return Err(Box::new(Error::new(
                        ErrorKind::InvalidInput,

View on GitHub (pinned to 900007c480)