jdx/mise · error
{tool}'s bin/install exited successfully but installed nothi
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 verifies the install path is non-empty. If the script exits 0 but leaves $ASDF_INSTALL_PATH empty, the install is treated as a silent failure — asdf plugins are expected to fail non-zero when their build fails — so mise raises this error naming the tool and the (display-path-formatted) install directory.
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 afd2eddd3a)
Solutions
- Inspect/fix the plugin's bin/install so it writes into $ASDF_INSTALL_PATH and exits non-zero on failure (add `set -euo pipefail`).
- Re-run the install and check the plugin's logs for a masked download/build failure.
- Update or reinstall the plugin (`mise plugin update <tool>` or remove/re-add) to get a working version.
- Use a core/backend implementation of the tool instead of the asdf plugin if available.
Example fix
// before (bin/install) curl -fsSL $download_url -o $ASDF_INSTALL_PATH/bin/tool || true // after (bin/install) set -euo pipefail mkdir -p "$ASDF_INSTALL_PATH/bin" curl --fail -fsSL "$download_url" -o "$ASDF_INSTALL_PATH/bin/tool" chmod +x "$ASDF_INSTALL_PATH/bin/tool"
Defensive patterns
Strategy: fallback
Validate before calling
# sanity-check plugin install output location before relying on it mise plugin list --urls ls "$(mise where "$TOOL" 2>/dev/null)" 2>/dev/null || echo 'nothing installed'
Try / catch
if ! mise install "$TOOL@$VER"; then echo "asdf plugin produced empty install; updating plugin" mise plugin update "$TOOL" && mise install "$TOOL@$VER" fi
Prevention
- Write plugin bin/install scripts with `set -euo pipefail` and explicit non-zero exits on failure.
- Always install into $ASDF_INSTALL_PATH, never a hardcoded directory.
- Test plugins by checking the install dir is non-empty after a successful run.
- Keep plugins updated; stale plugins are the usual cause of silent no-op installs.
When it happens
Trigger: `mise install <asdf-plugin-tool>@<version>` where the plugin's bin/install exits successfully without writing anything into $ASDF_INSTALL_PATH; called from install_version_ via verify_install_script_output.
Common situations: Broken or stale asdf plugin whose download failed but script masked the error; plugin written for a different layout (installs to a wrong directory); plugin bug where a build step silently no-ops; plugin lacks strict `set -e` behavior so failures are swallowed.
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 '{plugin_name}' exists but '{tool_name}' is not
- error running {}: exited with code {} {}
- error running {}: terminated by signal {}
- Paranoid mode is enabled, refusing to install community-deve
- {ba} is not installed
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/68715511d7b2bd4f.
Report an issue: GitHub.