jdx/mise · error

[bootstrap.directories]."{}": recursive is only valid with s

Error message

[bootstrap.directories]."{}": recursive is only valid with state = "absent"

What it means

Raised by ManagedDirectoryRequest::from_toml for [bootstrap.directories] entries. `recursive = true` (recursive removal of the tree) is only meaningful when state = "absent"; combining it with state = "present" is contradictory — creation has no meaningful notion of recursion via this flag — so the entry is rejected at parse time.

Source

Thrown at src/system/managed_files.rs:642

        crate::file::replace_path(source)
    } else {
        PathBuf::from(source)
    };
    if source.is_absolute() {
        source
    } else {
        base.join(source)
    }
}

impl ManagedDirectoryRequest {
    fn from_toml(
        path: PathBuf,
        config: ManagedDirectoryTomlConfig,
        origin: ResourceOrigin,
    ) -> Result<Self> {
        if config.state == ManagedState::Present && config.recursive {
            bail!(
                "[bootstrap.directories].\"{}\": recursive is only valid with state = \"absent\"",
                path.display()
            );
        }
        Ok(Self {
            path,
            owner: nonempty("owner", config.owner)?,
            group: nonempty("group", config.group)?,
            mode: parse_mode(config.mode.as_deref(), 0o755)?,
            state: config.state,
            recursive: config.recursive,
            replace: config.replace,
            notify: config.notify,
            origin,
            inspection: None,
        })
    }

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Remove `recursive = true` from the present-state directory entry (creating a directory already creates parents).
  2. If you intended recursive removal of the tree, set state = "absent" and keep recursive = true.
  3. Re-run bootstrap to confirm the config parses.

Example fix

# before
[[bootstrap.directories]]
path = "/var/lib/myapp/cache"
state = "present"
recursive = true

# after
[[bootstrap.directories]]
path = "/var/lib/myapp/cache"
state = "present"
Defensive patterns

Strategy: validation

Validate before calling

fn validate_directory_entry(entry: &ManagedDirectoryTomlConfig) -> Result<(), String> {
    if entry.state == ManagedState::Present && entry.recursive {
        return Err("recursive is only valid with state = \"absent\"".into());
    }
    Ok(())
}

Type guard

fn invalid_recursive(entry: &ManagedDirectoryTomlConfig) -> bool {
    entry.state == ManagedState::Present && entry.recursive
}

Prevention

When it happens

Trigger: Parsing a [bootstrap.directories."<path>"] TOML entry where `recursive = true` AND state = "present" (or present is the default state).

Common situations: Copying an absent-removal entry and flipping state to "present" without removing `recursive`; assuming `recursive = true` creates parent directories and setting it on a create entry; bulk-generating entries where the flag leaks across entries.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/9db22ad810fc4432. Report an issue: GitHub.