helix-editor/helix · error · anyhow::Error

Expected 'inherits' to be a string: {}

Error message

Expected 'inherits' to be a string: {}

What it means

Theme::load_theme reads each theme TOML and, if an 'inherits' key exists, requires it to be a string naming the parent theme; toml Values of other types (array, integer, boolean) fail with "Expected 'inherits' to be a string: {value}". The string is then resolved recursively — 'default' and 'base16_default' are built in, anything else loads from the themes directories, with cycle detection via visited_paths.

Source

Thrown at helix-view/src/theme.rs:154

    /// Recursively load a theme, merging with any inherited parent themes.
    ///
    /// The paths that have been visited in the inheritance hierarchy are tracked
    /// to detect and avoid cycling.
    ///
    /// It is possible for one file to inherit from another file with the same name
    /// so long as the second file is in a themes directory with lower priority.
    /// However, it is not recommended that users do this as it will make tracing
    /// errors more difficult.
    fn load_theme(&self, name: &str, visited_paths: &mut HashSet<PathBuf>) -> Result<Value> {
        let path = self.path(name, visited_paths)?;

        let theme_toml = self.load_toml(path)?;

        let inherits = theme_toml.get("inherits");

        let theme_toml = if let Some(parent_theme_name) = inherits {
            let parent_theme_name = parent_theme_name.as_str().ok_or_else(|| {
                anyhow!("Expected 'inherits' to be a string: {}", parent_theme_name)
            })?;

            let parent_theme_toml = match parent_theme_name {
                // load default themes's toml from const.
                "default" => DEFAULT_THEME_DATA.clone(),
                "base16_default" => BASE16_DEFAULT_THEME_DATA.clone(),
                _ => self.load_theme(parent_theme_name, visited_paths)?,
            };

            self.merge_themes(parent_theme_toml, theme_toml)
        } else {
            theme_toml
        };

        Ok(theme_toml)
    }

    pub fn read_names(path: &Path) -> Vec<String> {

View on GitHub (pinned to 079a789e8c)

Solutions

  1. Make inherits a single string: inherits = "default".
  2. To layer multiple customizations, chain single-parent inherits (child inherits parent which inherits grandparent).
  3. Remove the inherits key entirely for a fully self-contained theme.

Example fix

# before (themes/mytheme.toml)
 inherits = ["default", "base16_default"]

# after
 inherits = "default"
Defensive patterns

Strategy: validation

Validate before calling

fn inherits_is_string(toml: &toml::Value) -> Result<Option<&str>> {
    match toml.get("inherits") {
        None => Ok(None),
        Some(v) => v.as_str().map(Some).ok_or_else(|| anyhow!(
            "theme 'inherits' must be a single string, got: {v}"
        )),
    }
}

Type guard

fn inherits_name(theme: &toml::Value) -> Option<&str> {
    theme.get("inherits»).and_then(|v| v.as_str())
}

Try / catch

let inherits = match theme_toml.get("inherits") {
    Some(v) => Some(v.as_str().ok_or_else(|| anyhow!("theme {}: 'inherits' must be a string, got {v}", path.display()))?),
    None => None,
};

Prevention

When it happens

Trigger: A theme file containing inherits = ["default"] (array), inherits = 1, or inherits = true; YAML-style or copy-paste artifacts around the value; also valid-string cases where the named parent cannot be found surface as the sibling path-resolution error instead.

Common situations: Users trying multiple inheritance by listing several parents (unsupported — one string only); machine-generated themes emitting non-string scalars; editing theme files in tooling that auto-quotes or converts values.

Related errors


AI-assisted analysis of helix-editor/helix@079a789e8c (2026-08-16). Data as JSON: /api/errors/8af22b1800cc6f9f. Report an issue: GitHub.