jdx/mise · error
cannot write task stub because {} is a symbolic link
Error message
cannot write task stub because {} is a symbolic link What it means
The target stub path (bin/<task> or bin/<parent>/_default) is a symbolic link. Writing through a symlink would modify whatever it points at, which mise cannot treat as its own output, so generation stops and names the link.
Source
Thrown at src/cli/generate/task_stubs.rs:222
migrations.insert(StubMigration::File(stub.legacy_path.clone()));
}
Ok(metadata) if metadata.file_type().is_dir() => {}
Ok(_) => bail!(
"cannot create nested task stubs because {} is not a directory",
display_path(&stub.legacy_path)
),
Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}
Err(err) => return Err(err.into()),
}
}
for stub in stubs {
match fs::symlink_metadata(&stub.path) {
Ok(metadata) if metadata.file_type().is_dir() => {
validate_generated_stub_directory(&stub.path, &stub.output, stub.task)?;
migrations.insert(StubMigration::Directory(stub.path.clone()));
}
Ok(metadata) if metadata.file_type().is_symlink() => bail!(
"cannot write task stub because {} is a symbolic link",
display_path(&stub.path)
),
Ok(metadata) if metadata.file_type().is_file() => {
let existing = file::read_to_string(&stub.path)?;
let legacy_leaf = stub.legacy_path == stub.path && existing == stub.legacy_output;
if existing != stub.output && !legacy_leaf {
bail!(
"cannot write task stub because {} is not a generated task stub",
display_path(&stub.path)
);
}
}
Ok(_) => bail!(
"cannot write task stub because {} is not a regular file",
display_path(&stub.path)
),
Err(err) if matches!(err.kind(), ErrorKind::NotFound | ErrorKind::NotADirectory) => {}View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Remove the symlink (`git rm bin/<task>` for tracked, plain `rm` otherwise) and rerun `mise generate task-stubs`
- If the link is load-bearing, rename the task or change --dir so they no longer collide
- Adopt the committed-stub workflow the command exists for: generated stubs plus `mise generate bootstrap` replace symlink farms
Example fix
# before $ ls -l bin/build # bin/build -> ../tools/build $ mise generate task-stubs # error: bin/build is a symbolic link # after $ git rm bin/build $ mise generate task-stubs
Defensive patterns
Strategy: type-guard
Validate before calling
#!/bin/bash
# refuse to generate over symlinks
find bin -type l -print -quit | grep -q . && { echo 'symlink under bin/' >&2; exit 1; }
mise generate task-stubs Type guard
is_writable_path() {
# 0 when path is absent or a real file/dir (not a symlink)
[ ! -L "$1" ] && { [ ! -e "$1" ] || [ -f "$1" ] || [ -d "$1" ]; }
} Prevention
- Retire symlink-farm bin/ layouts before adopting task-stubs; commit generated stubs instead
- Add a CI check (`find bin -type l`) so symlinks cannot sneak back in
When it happens
Trigger: `mise generate task-stubs` when bin/<task> is a symlink to elsewhere — e.g. a repo still using the bin/-full-of-symlinks convention (bin/foo -> ../tools/foo).
Common situations: Migrating a repo from symlink-style bin/ dispatch to committed stubs; contributors with divergent bin/ setups; symlinks created by an installer script.
Related errors
- multiple tasks map to task stub path {}
- cannot create nested task stubs because {} is not the genera
- cannot create nested task stubs because {} is not a director
- cannot write task stub because {} is not a generated task st
- cannot write task stub because {} is not a regular file
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/64dcc5e99831a462.
Report an issue: GitHub.