jdx/mise · error · eyre::Report
target is not the managed symlink, use --force to remove it
Error message
target is not the managed symlink, use --force to remove it
What it means
A `symlink`-mode entry's target exists but is a regular file or directory rather than a symlink, so mise has no ownership evidence (a real file may hold user data) and refuses removal unless `--force` is given.
Source
Thrown at src/system/files.rs:1546
FileMode::Symlink
if !(cfg!(windows) && req.source.is_file() && !req.target.is_symlink()) =>
{
if req.target.is_symlink() {
let dest = std::fs::read_link(&req.target)?;
if opts.force || dest == req.source || points_at_same_file(&req.target, &req.source)
{
paths.insert(req.target.clone(), ());
} else {
bail!(
"target symlink points to {}, use --force to remove it",
dest.display_user()
);
}
} else if req.target.exists() {
if opts.force {
paths.insert(req.target.clone(), ());
} else {
bail!("target is not the managed symlink, use --force to remove it");
}
}
}
FileMode::SymlinkEach if !cfg!(windows) => {
clear_symlink_each_state = symlink_each_state_path(req).exists();
if req.target.is_symlink() || (req.target.exists() && !req.target.is_dir()) {
if opts.force {
paths.insert(req.target.clone(), ());
} else {
bail!("target is not the managed directory, use --force to remove it");
}
} else if req.target.is_dir() {
for path in owned_links(req)? {
paths.insert(path, ());
}
cleanup_empty_dirs = true;
}
}View on GitHub (pinned to 6f52dcdf99)
Solutions
- Back up any wanted edits (`cp ~/.gitconfig ~/gitconfig.bak`), then re-run with `--force`
- Or restore mise ownership first: `mise bootstrap dotfiles apply` recreates the symlink, after which unapply verifies normally
- Merge hand edits back into the dotfiles source before forcing
Example fix
# before: target is a real file, not the managed symlink $ ls -l ~/.gitconfig -rw-r--r-- 1 me me 412 ~/.gitconfig $ mise bootstrap dotfiles unapply Error: target is not the managed symlink, use --force to remove it # after: keep edits, then force-remove $ cp ~/.gitconfig ~/gitconfig.bak && git -C ~/dotfiles diff # salvage edits $ mise bootstrap dotfiles unapply --force
Defensive patterns
Strategy: validation
Validate before calling
# Fail early when a symlink-mode target is not a symlink. for t in ~/.gitconfig ~/.vimrc; do [ -e "$t" ] && [ ! -L "$t" ] && echo "NOT A SYMLINK: $t" && exit 1 done
Type guard
fn is_not_managed_symlink(err: &miette::Report) -> bool {
err.to_string()
.starts_with("target is not the managed symlink")
} Prevention
- Configure editors to follow symlinks on save (e.g. vim 'writebackup' settings) instead of replacing them
- After switching an entry's mode, always re-apply before unapplying
- Check `ls -l` on managed targets periodically to spot replaced links
When it happens
Trigger: `unapply` where the target exists (`req.target.exists()`) but `is_symlink()` is false — the link was replaced by a real file (some editors 'unlink and save'), or the entry previously ran in copy/content mode and the mode was switched to symlink without re-apply.
Common situations: Editor replaced the symlink with a copy of the file; user did `cp realfile ~/.gitconfig` over the link; mode churn in mise.toml without a re-apply in between.
Related errors
- target symlink points to {}, use --force to remove it
- no dotfiles matched target filter: {}
- files: cannot unapply these entries:\n{}
- target is not the managed directory, use --force to remove i
- source directory is missing, so managed children cannot be i
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/c24905f7b272248a.
Report an issue: GitHub.