jdx/mise · error · eyre::Report

[bootstrap.files]." ": present files require source or…

Error message

[bootstrap.files]."{}": present files require source or content

What it means

During ManagedFile construction, a file declared with state = "present" must say what its body should be: from_toml requires either source or content and bails when both are None. Absent-state files legitimately have no body, so the requirement applies only to Present files.

Solutions

  1. Add a `content` string with the desired file body.
  2. Or add a `source` path pointing to the file/template to copy.
  3. Or set state = "absent" if the file only needs to be removed.

Example fix

# before
[bootstrap.files."/etc/app.conf"]
state = "present"

# after
[bootstrap.files."/etc/app.conf"]
content = "key = value"
state = "present"
Defensive patterns

Strategy: validation

Validate before calling

// rust
fn validate_body(entry: &FileEntry) -> Result<(), &'static str> {
    if entry.state == State::Present && entry.source.is_none() && entry.content.is_none() {
        return Err("present files require source or content");
    }
    Ok(())
}

Prevention

When it happens

Trigger: Parsing a [bootstrap.files] entry whose match arm is (None, None, ManagedState::Present) — i.e. neither `source` nor `content` set while state = "present".

Common situations: Adding a file entry as a placeholder before filling in its body; deleting the content key when switching to a source but forgetting to add the source; a state defaulting to present after removing an explicit absent declaration.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/28892a6d63b908a7. Report an issue: GitHub.

Appendix: source

Thrown at src/system/managed_files.rs:612

        let mut content = match (config.source, config.content, config.state) {
            (Some(_), Some(_), _) => {
                bail!(
                    "[bootstrap.files].\"{}\": source and content are mutually exclusive",
                    path.display()
                )
            }
            (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, &origin.config))
                .transpose()
                .wrap_err_with(|| {
                    format!(
                        "[bootstrap.files].\"{}\": failed to render template",
                        path.display()

View on GitHub (pinned to 533346cc37)