jdx/mise · error

present file has content

Error message

present file has content

What it means

This is a Rust `.expect()` panic, not a catchable error. It fires when a managed file is marked `ManagedState::Present` while building the privileged `WriteFile` action, but its `content` field is `None`. The codebase's invariant is that any file declared Present must carry the content to write; a None here means the file was constructed incoherently.

Solutions

  1. Set the `content` field whenever `state` is `ManagedState::Present` before invoking the apply path
  2. Validate the file entry at construction/deserialization time and reject Present-without-content early with a real error
  3. Switch the state to `ManagedState::Absent` if the file should only be removed, not written

Example fix

// before
ManagedFile { path, state: ManagedState::Present, content: None, .. }
// after
ManagedFile { path, state: ManagedState::Present, content: Some(expected_content), .. }
Defensive patterns

Strategy: validation

Validate before calling

fn validate_managed_file(f: &ManagedFile) -> Result<()> {
    if f.state == ManagedState::Present && f.content.is_none() {
        return Err(anyhow!("file {} marked Present but has no content", f.path.display()));
    }
    Ok(())
}

Type guard

fn has_content(f: &ManagedFile) -> bool {
    f.state != ManagedState::Present || f.content.is_some()
}

Prevention

When it happens

Trigger: Calling the managed-file apply/plan path (src/system/managed_files.rs:673) with a `ManagedFile` whose `state` is `Present` but whose `content` was never set (constructed programmatically or deserialized from a config/partial state that omitted `content`).

Common situations: Hand-constructing a ManagedFile in a plugin or test; a config schema change that drops the `content` field; deserializing state from an older/other tool version that allowed Present without content.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at src/system/managed_files.rs:673

    }

    fn operation(&self) -> Result<Option<PrivilegedAction>> {
        match self.plan()?.action {
            ResourceAction::Noop => return Ok(None),
            ResourceAction::Unknown if self.state == ManagedState::Absent => bail!(
                "refusing to remove directory {} as a file; declare it in [bootstrap.directories]",
                self.path.display()
            ),
            ResourceAction::Unknown => bail!(
                "refusing to replace non-file path {}; set replace = true to allow replacement",
                self.path.display()
            ),
            _ => {}
        }
        Ok(Some(match self.state {
            ManagedState::Present => PrivilegedAction::WriteFile {
                path: self.path.clone(),
                content: self.content.clone().expect("present file has content"),
                owner: self.owner.clone(),
                group: self.group.clone(),
                mode: self.mode,
                replace: self.replace,
            },
            ManagedState::Absent => PrivilegedAction::RemoveFile {
                path: self.path.clone(),
            },
        }))
    }
}

fn resolve_source_path(base: &Path, source: &str) -> PathBuf {
    let source = if source.starts_with("~/") {
        crate::file::replace_path(source)
    } else {
        PathBuf::from(source)
    };

View on GitHub (pinned to 533346cc37)