asdf-vm/asdf · error

failed to run download callback: %w

Error message

failed to run download callback: %w

What it means

InstallOneVersion invokes the plugin's `download` callback (the plugin script's download command) with env including ASDF_DOWNLOAD_PATH. NoCallbackError is tolerated (plugin has no download step), but any other non-nil error is wrapped as 'failed to run download callback', meaning the plugin's own download script failed. The plugin's stdout/stderr already carried the underlying diagnostics.

Source

Thrown at internal/versions/versions.go:184

		"ASDF_INSTALL_VERSION": version.Value,
		"ASDF_INSTALL_PATH":    installDir,
		"ASDF_DOWNLOAD_PATH":   downloadDir,
		"ASDF_CONCURRENCY":     concurrency,
	}

	err = os.MkdirAll(downloadDir, 0o777)
	if err != nil {
		return fmt.Errorf("unable to create download dir: %w", err)
	}

	err = hook.RunWithOutput(conf, fmt.Sprintf("pre_asdf_download_%s", plugin.Name), []string{version.Value}, stdOut, stdErr)
	if err != nil {
		return fmt.Errorf("failed to run pre-download hook: %w", err)
	}

	err = plugin.RunCallback("download", []string{}, env, stdOut, stdErr)
	if _, ok := err.(plugins.NoCallbackError); err != nil && !ok {
		return fmt.Errorf("failed to run download callback: %w", err)
	}

	err = hook.RunWithOutput(conf, fmt.Sprintf("pre_asdf_install_%s", plugin.Name), []string{version.Value}, stdOut, stdErr)
	if err != nil {
		return fmt.Errorf("failed to run pre-install hook: %w", err)
	}

	err = os.MkdirAll(installDir, 0o777)
	if err != nil {
		return fmt.Errorf("unable to create install dir: %w", err)
	}

	err = plugin.RunCallback("install", []string{}, env, stdOut, stdErr)
	if err != nil {
		if rmErr := os.RemoveAll(installDir); rmErr != nil {
			fmt.Fprintf(stdErr, "failed to clean up '%s' due to %s\n", installDir, rmErr)
		}
		return fmt.Errorf("failed to run install callback: %w", err)

View on GitHub (pinned to 074a1722ca)

Solutions

  1. Re-run with the plugin's stderr visible — the actual cause (HTTP error, bad URL) is printed by the plugin script
  2. Check network/proxy connectivity to the download URL
  3. Verify the requested version exists for the plugin; update the plugin (`asdf plugin update <name>`)
  4. Install missing dependencies the plugin's download script needs (curl, git, tar, etc.)
Defensive patterns

Strategy: retry

Validate before calling

// ensure required tools exist before install:
for _, bin := range []string{"curl", "git", "tar"} {
    if _, err := exec.LookPath(bin); err != nil {
        return fmt.Errorf("missing dependency: %s", bin)
    }
}

Try / catch

if err != nil && strings.Contains(err.Error(), "failed to run download callback") {
    // check network, then retry with backoff
}

Prevention

When it happens

Trigger: plugin.RunCallback("download", ...) returns an error that is not NoCallbackError — the plugin's download script exits non-zero (curl failure, bad URL, checksum mismatch, missing download tool).

Common situations: Network failures or blocked downloads, plugin pointing at a version that no longer exists upstream, missing system deps (curl/tar), corrupted ASDF_DOWNLOAD_PATH contents.

Related errors


AI-assisted analysis of asdf-vm/asdf@074a1722ca (2026-08-30). Data as JSON: /api/errors/462aaf132e38e1bf. Report an issue: GitHub.