jdx/mise · error

[bootstrap.files]."{}": absent files must not declare source

Error message

[bootstrap.files]."{}": absent files must not declare source or content

What it means

Raised by ManagedFileRequest::from_toml when a [bootstrap.files] entry declares state="absent" but also supplies `source` or `content`. Deletion only needs the path; providing a body for a file the library is asked to remove is contradictory, so the entry is rejected at parse time.

Source

Thrown at src/system/managed_files.rs:557

                )
            }
            (Some(source), None, ManagedState::Present) => {
                let source = resolve_source_path(base, &source);
                Some(fs::read_to_string(&source).wrap_err_with(|| {
                    format!(
                        "[bootstrap.files].\"{}\": failed to read source {}",
                        path.display(),
                        source.display()
                    )
                })?)
            }
            (None, Some(content), ManagedState::Present) => Some(content),
            (None, None, ManagedState::Present) => bail!(
                "[bootstrap.files].\"{}\": present files require source or content",
                path.display()
            ),
            (None, None, ManagedState::Absent) => None,
            (_, _, ManagedState::Absent) => bail!(
                "[bootstrap.files].\"{}\": absent files must not declare source or content",
                path.display()
            ),
        };
        if config.template {
            let rendered = content
                .as_deref()
                .map(|content| secrets.render(root_config, content, base, &path))
                .transpose()
                .wrap_err_with(|| {
                    format!(
                        "[bootstrap.files].\"{}\": failed to render template",
                        path.display()
                    )
                })?;
            content = rendered;
        }
        Ok(Self {

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Remove the `source` and `content` keys from the absent-state entry, keeping only path and state.
  2. If you actually want the file to exist with that body, set state = "present" instead.
  3. Re-run bootstrap to confirm the config parses.

Example fix

# before
[[bootstrap.files]]
path = "/etc/legacy.conf"
content = "old settings"
state = "absent"

# after
[[bootstrap.files]]
path = "/etc/legacy.conf"
state = "absent"
Defensive patterns

Strategy: validation

Validate before calling

fn validate_file_entry(entry: &ManagedFileTomlConfig) -> Result<(), String> {
    if entry.state == ManagedState::Absent && (entry.source.is_some() || entry.content.is_some()) {
        return Err("absent files must not declare source or content".into());
    }
    Ok(())
}

Type guard

fn absent_with_body(entry: &ManagedFileTomlConfig) -> bool {
    entry.state == ManagedState::Absent && (entry.source.is_some() || entry.content.is_some())
}

Prevention

When it happens

Trigger: Parsing a [bootstrap.files."<path>"] TOML entry with state = "absent" where `source` and/or `content` is set — the (_, _, ManagedState::Absent) catch-all arm after the (None, None, Absent) case.

Common situations: Duplicating an existing present-file block and changing only state to "absent" without removing the body keys; a cleanup entry written by copying a template config that always includes `content`; bulk-generating entries where absent/present is data-driven and body keys leak into absent ones.

Related errors


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