jdx/mise · error

files: cannot unapply these entries:\n{}

Error message

files: cannot unapply these entries:\n{}

What it means

Thrown by `mise bootstrap dotfiles unapply` during the first, render-free planning pass over `[dotfiles]` entries. Every entry is planned before anything is deleted; each entry that cannot be verified as mise-owned (drifted content, missing source, foreign symlink, wrong file type) is collected into one aggregate error with a `[dotfiles]."<target>": <reason>` line per failure. The command is all-or-nothing: when this fires, nothing has been removed.

Source

Thrown at src/system/files.rs:1384

/// Remove configured whole-file entries without recursively deleting
/// directories that may contain unmanaged files. Symlinks carry their own
/// ownership evidence. Copies and templates must still match their source
/// unless `--force` was given.
pub(crate) fn plan_unapply<'a>(
    requests: &'a [FileRequest],
    opts: &UnapplyOpts,
) -> Result<Vec<UnapplyPlan<'a>>> {
    let mut todo = vec![];
    let mut problems = vec![];
    for req in requests {
        match plan_unapply_one(req, opts) {
            Ok(Some(plan)) => todo.push(plan),
            Ok(None) => {}
            Err(err) => problems.push(format!("  [dotfiles].\"{}\": {err}", req.target_raw)),
        }
    }
    if !problems.is_empty() {
        bail!(
            "files: cannot unapply these entries:\n{}",
            problems.join("\n")
        );
    }
    Ok(todo)
}

/// Resolve checks that may execute user-authored template functions. This runs
/// only after interactive confirmation, but still before any mutation.
pub(crate) fn resolve_unapply(
    config: &Config,
    plans: &mut Vec<UnapplyPlan<'_>>,
    opts: &UnapplyOpts,
) -> Result<()> {
    if opts.dry_run {
        return Ok(());
    }
    let mut problems = vec![];

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Read each ` [dotfiles]."<target>": <reason>` line and fix that specific entry: restore the missing source or run `mise bootstrap dotfiles apply` so targets match again
  2. Re-check after each fix with `mise bootstrap dotfiles unapply --dry-run` (inert, shows the remaining failures)
  3. If the drifted targets are disposable, re-run with `--force` to skip ownership verification
  4. Delete `[dotfiles]` entries you no longer manage so unapply stops planning them

Example fix

# before: source was deleted from the dotfiles repo
$ rm ~/dotfiles/zshrc
$ mise bootstrap dotfiles unapply
Error: files: cannot unapply these entries:
  [dotfiles]."~/.zshrc": source is missing; use --force to remove the target

# after: restore the source, verify with dry-run, then unapply
$ git -C ~/dotfiles checkout -- zshrc
$ mise bootstrap dotfiles unapply --dry-run
$ mise bootstrap dotfiles unapply
Defensive patterns

Strategy: validation

Validate before calling

#!/usr/bin/env bash
# Gate the real unapply on an inert dry-run so failures surface before
# anything is at risk (run in CI or before manual runs).
set -euo pipefail
if ! mise bootstrap dotfiles unapply --dry-run; then
  echo "unapply plan failed; fix the entries above or pass --force deliberately" >&2
  exit 1
fi
mise bootstrap dotfiles unapply --yes

Type guard

// Rust (embedding mise internals): detect this aggregate bail.
fn is_unapply_plan_refused(err: &miette::Report) -> bool {
    err.to_string()
        .starts_with("files: cannot unapply these entries")
}

Try / catch

// Rust: treat planning failure as a hard stop; nothing was mutated,
// so report and re-run after fixing entries (never ignore).
match files::plan_unapply(&reqs, &opts) {
    Ok(plans) => { /* proceed to resolve/execute */ }
    Err(err) if is_unapply_plan_refused(&err) => {
        eprintln!("{err:?}");
        std::process::exit(1);
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: Running `mise bootstrap dotfiles unapply` (optionally with target filters) when at least one entry fails `plan_unapply_one`: a copy/template target whose bytes differ from its source, a symlink pointing somewhere other than the configured source, a source file deleted from the dotfiles repo, or a non-directory target for a directory-backed mode.

Common situations: Hand-editing a managed file after apply; renaming/moving the dotfiles source without re-applying; switching an entry's mode (copy->symlink) so the on-disk target no longer matches; another dotfile manager (stow, home-manager) having replaced targets.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/3dfd488b7dba640f. Report an issue: GitHub.