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

Failed to deserialize theme: {}

Error message

Failed to deserialize theme: {}

What it means

Thrown by ThemeManager::load_theme_from_config when the config crate's try_deserialize() of the theme TOML into ThemeConfig fails. It is wrapped in io::ErrorKind::InvalidInput, and the underlying cause string is redacted to 'set theme debug on for more info' unless debug was enabled in ThemeManager::new (wired to the theme.debug setting in config, settings.rs:1532). Like error 0, ThemeManager::load_theme catches it and degrades to the '(none)' theme, so users see a warning log with the theme silently not applied.

Source

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

            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 202f6ad98e)

Solutions

  1. Set theme.debug = true in config.toml to get the full deserialization error message in the warning
  2. Fix the reported key/type in the theme TOML so it matches the ThemeConfig schema (colors as strings keyed by meaning, theme.name/theme.parent as strings)
  3. Copy a working theme (e.g. the default theme file from the Atuin repo) and modify it incrementally
  4. Rename or remove the broken {name}.toml so the fallback to built-in themes is explicit

Example fix

# before (themes/mytheme.toml)
[theme]
name = "mytheme"
[colors]
error = "red"        # unknown key 'error'

# after
[theme]
name = "mytheme"
[colors]
AlertError = "red"   # valid Meaning key, string value
Defensive patterns

Strategy: validation

Validate before calling

// Validate theme TOML against the schema before Atuin loads it
let raw = std::fs::read_to_string(theme_path)?;
let value: toml::Value = raw.parse()?;           // syntax check
let colors = value.get("colors").and_then(|c| c.as_table());
if colors.is_none() { /* schema mismatch: fix before shipping the theme */ }

Type guard

fn is_valid_theme_config(v: &toml::Value) -> bool {
    v.get("theme")
        .and_then(|t| t.get("name"))
        .and_then(|n| n.as_str())
        .is_some()
        && v.get("colors")
            .and_then(|c| c.as_table())
            .is_some_and(|t| t.values().all(|v| v.as_str().is_some()))
}

Try / catch

match manager.load_theme_from_file(name, 10) {
    Ok(t) => t,
    Err(e) if e.to_string().contains("Failed to deserialize theme") => {
        // enable theme.debug for details, fall back to a builtin theme meanwhile
        manager.load_theme("default", None)
    }
    Err(e) => { /* propagate */ manager.load_theme("(none)", None) }
}

Prevention

When it happens

Trigger: A {name}.toml in the themes directory whose [theme] or colors table does not match ThemeConfig: unknown color keys (not valid Meaning variants), non-string color values, a missing or wrongly-typed theme.name or theme.parent, or a file that built as a Config but fails typed deserialization. Also reachable via load_theme_from_config directly with a programmatically built Config.

Common situations: Hand-editing a theme TOML and typos like `colour` instead of color keys, `red = "Meaning::AlertError"` inverted key/value order, using a theme written for a newer/older Atuin with a changed schema, or trailing types like integers where color strings are expected. Users migrating custom themes between Atuin versions frequently hit this.

Related errors


AI-assisted analysis of atuinsh/atuin@202f6ad98e (2026-08-16). Data as JSON: /api/errors/eb7ad4c3591e7da0. Report an issue: GitHub.