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
- Enable debug mode to surface the underlying deserializer error message, then fix the offending key/type in the theme file.
- Validate the theme file's TOML syntax and that every field matches ThemeConfig's expected types (colors: map of meaning -> string; parent: optional string).
- Compare against a known-good stock theme file and remove unsupported keys.
- 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
- Enable debug logging once to see the exact deserializer message
- Edit theme files starting from a stock theme rather than from scratch
- After Atuin upgrades, re-check custom themes against schema changes
- Run the TOML file through a linter/validator before using it
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
- Could not deserialize config
- Empty theme directory override and could not find theme…
- Parent requested but we hit the recursion limit
- Config key must be non-empty and must not contain whitespace
- Could not build config
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)