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

Parent requested but we hit the recursion limit

Error message

Parent requested but we hit the recursion limit

What it means

Thrown by ThemeManager::load_theme_from_config when a theme declares theme.parent but the recursion budget max_depth has hit 0. Depth starts at DEFAULT_MAX_DEPTH (10, theme.rs:12) and each parent hop calls load_theme with max_depth - 1, so any inheritance chain longer than 10, or a cycle (a parent of b, b parent of a), exhausts the budget. It is an io::ErrorKind::InvalidInput; via ThemeManager::load_theme it is caught and falls back to '(none)'.

Source

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

            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,
                        "Parent requested but we hit the recursion limit",
                    )));
                }
                Some(self.load_theme(parent_name.as_str(), Some(max_depth - 1)))
            }
            None => Some(self.load_theme("default", Some(max_depth - 1))),
        };

        if debug && name != theme_config.theme.name {
            tracing::warn!(
                "Your theme config name is not the name of your loaded theme {} != {}",
                name,
                theme_config.theme.name
            );
        }

        let theme = Theme::from_foreground_colors(theme_config.theme.name, parent, colors, debug);

View on GitHub (pinned to 202f6ad98e)

Solutions

  1. Flatten the theme inheritance chain to fewer than 10 hops
  2. Break the cycle: ensure no theme transitively lists itself as a parent (grep parent = in your themes directory and follow the chain)
  3. Set parent only to themes that exist and terminate (the default theme has no parent)
  4. Enable theme.debug to see the warn logs tracing which parent name was being loaded when the limit hit

Example fix

# before (themes/a.toml -> themes/b.toml -> themes/a.toml)
# a.toml: parent = "b" ; b.toml: parent = "a"  => cycle

# after (themes/b.toml)
[theme]
name = "b"
# parent = "a"   # removed; b now inherits from 'default'
[colors]
AlertError = "red"
Defensive patterns

Strategy: validation

Validate before calling

// Walk parent links before loading; reject cycles and over-deep chains
fn chain_depth(dir: &std::path::Path, name: &str, seen: &mut Vec<String>) -> Option<usize> {
    if seen.iter().any(|s| s == name) { return None; } // cycle
    seen.push(name.clone());
    let text = std::fs::read_to_string(dir.join(format!("{name}.toml")).ok()?;
    let v: toml::Value = text.parse().ok()?;
    match v.get("theme").and_then(|t| t.get("parent")).and_then(|p| p.as_str()) {
        Some(p) => chain_depth(dir, p, seen).map(|d| d + 1),
        None => Some(0),
    }
}
// require chain_depth(...) <= 10 before calling load_theme

Try / catch

match manager.load_theme_from_file(name, 10) {
    Ok(t) => t,
    Err(e) if e.to_string().contains("recursion limit") => {
        // inheritance chain too deep or cyclic: fall back to 'default'
        manager.load_theme("default", None)
    }
    Err(e) => { /* propagate or fallback */ manager.load_theme("(none)", None) }
}

Prevention

When it happens

Trigger: A theme chain of more than 10 files (child.toml -> ... -> 11th ancestor), or a circular parent reference where two themes name each other as parent. Each cycle iteration burns one depth level until max_depth == 0 at theme.rs:475 and the error returns.

Common situations: Users creating layered themes that inherit from one another and accidentally reintroducing an ancestor (a -> b -> c -> a); refactoring a theme family so a parent points back at its own child; excessively deep 'base' theme chains built by hand.

Related errors


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