jdx/mise · error
's bin/install exited successfully but installed nothing…
Error message
{tool}'s bin/install exited successfully but installed nothing into {}; check that the plugin installs into $ASDF_INSTALL_PATH and that it fails when the build fails What it means
After running an asdf plugin's bin/install script, mise checks the target install directory ($ASDF_INSTALL_PATH) and fails if it is empty. This catches plugins whose install script exits 0 without actually producing any files, which would otherwise silently install a broken/nonexistent tool. It exists because asdf plugins must fail loudly when their build fails.
Solutions
- Fix the plugin's bin/install to copy/build its artifacts into $ASDF_INSTALL_PATH (respect the env var; don't hardcode paths).
- Make bin/install exit non-zero when the download or build fails so mise never sees a successful no-op.
- Test the plugin with the version in question (e.g. run bin/install manually with ASDF_INSTALL_PATH set) and inspect what it produces.
- Check the plugin repository for a newer/patched release fixing the version's install script.
Example fix
# before (plugin bin/install) curl -fsSL "$download_url" -o /tmp/tool.tar.gz || true tar -xzf /tmp/tool.tar.gz # after mkdir -p "$ASDF_INSTALL_PATH" curl -fsSL "$download_url" -o /tmp/tool.tar.gz tar -xzf /tmp/tool.tar.gz -C "$ASDF_INSTALL_PATH" --strip-components=1
Defensive patterns
Strategy: validation
Validate before calling
# before trusting a plugin
ASDF_INSTALL_PATH=$(mktemp -d) "$plugin_dir/bin/install" || exit 1
[ -z "$(ls -A "$ASDF_INSTALL_PATH")" ] && { echo 'plugin installs nothing'; exit 1; } Prevention
- Always have bin/install write into $ASDF_INSTALL_PATH, never hardcoded paths
- Never swallow download/build failures with `|| true` in install scripts
- Test plugin installs for each supported version and platform before publishing
When it happens
Trigger: Calling `mise install <tool>@<version>` (install_version_ -> verify_install_script_output) for an asdf/vfox-style plugin whose bin/install script returns success but writes nothing into $ASDF_INSTALL_PATH.
Common situations: Writing a custom asdf plugin where the build silently no-ops (wrong download URL handled by `|| true`, build step skipped, or files written to a hardcoded path instead of $ASDF_INSTALL_PATH); upstream release asset 404s but the script masks it; plugin updated for a new version layout that no longer matches.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- asdf plugin ' ' exists but ' ' is not available or the…
- is not installed
- dotnet SDK was not found in `dotnet --list-sdks` output
- error running : exited with code
- error running : terminated by signal
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/68715511d7b2bd4f.
Report an issue: GitHub.
Appendix: source
Thrown at src/backend/asdf.rs:549
/// Verifies that `bin/install` actually put something in `$ASDF_INSTALL_PATH`.
///
/// `bin/install` is a plugin-supplied shell script, and one that installs nothing can still exit 0
/// — a missing `set -e`, a build that fails inside a pipeline, a download that 404s. mise would
/// otherwise report `✓ installed`, record the version in install state, and keep resolving to an
/// empty directory afterwards (#5288).
///
/// Emptiness is exact rather than a guess: `Backend::create_install_dirs` recreates the install
/// path immediately before the script runs, and the `incomplete` marker lives under the cache dir,
/// so anything present afterwards came from the plugin. It is also all that can be checked — asdf
/// plugins install into `bin/`, `libexec/`, an unpacked tarball root, or wherever the tool puts
/// things, so a stricter test (spm requires an executable in `bin/`) would reject working plugins.
///
/// There is no `system` case to exclude: anything reaching here has already been through
/// `script_man_for_tv`, which panics for `ToolRequest::System`.
fn verify_install_script_output(tool: &str, install_path: &Path) -> Result<()> {
if file::ls(install_path)?.is_empty() {
bail!(
"{tool}'s bin/install exited successfully but installed nothing into {}; check that the plugin installs into $ASDF_INSTALL_PATH and that it fails when the build fails",
file::display_path(install_path)
);
}
Ok(())
}
impl Debug for AsdfBackend {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AsdfPlugin")
.field("name", &self.name)
.field("plugin_path", &self.plugin_path)
.field("cache_path", &self.ba.cache_path)
.field("downloads_path", &self.ba.downloads_path)
.field("installs_path", &self.ba.installs_path)
.field("repo_url", &self.repo_url)
.finish()
}View on GitHub (pinned to 533346cc37)