{"record":{"id":"701c12640be16f9b","repo":"asdf-vm/asdf","slug":"failed-to-run-download-callback-w","errorCode":null,"errorMessage":"failed to run download callback: %w","messagePattern":"failed to run download callback: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/installtest/installtest.go","lineNumber":51,"sourceCode":"\tdownloadDir := DownloadPath(conf, plugin, version)\n\tinstallDir := InstallPath(conf, plugin, version)\n\n\tenv := map[string]string{\n\t\t\"ASDF_INSTALL_TYPE\":    versionType,\n\t\t\"ASDF_INSTALL_VERSION\": version,\n\t\t\"ASDF_INSTALL_PATH\":    installDir,\n\t\t\"ASDF_DOWNLOAD_PATH\":   downloadDir,\n\t\t\"ASDF_CONCURRENCY\":     \"1\",\n\t}\n\n\terr = os.MkdirAll(downloadDir, 0o777)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create download dir: %w\", err)\n\t}\n\n\terr = plugin.RunCallback(\"download\", []string{}, env, &stdOut, &stdErr)\n\tif _, ok := err.(plugins.NoCallbackError); err != nil && !ok {\n\t\treturn fmt.Errorf(\"failed to run download callback: %w\", err)\n\t}\n\n\terr = os.MkdirAll(installDir, 0o777)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to create install dir: %w\", err)\n\t}\n\n\terr = plugin.RunCallback(\"install\", []string{}, env, &stdOut, &stdErr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to run install callback: %w\", err)\n\t}\n\n\treturn nil\n}\n\n// InstallPath returns the path to a tool installation\nfunc InstallPath(conf config.Config, plugin plugins.Plugin, version string) string {\n\treturn filepath.Join(pluginInstallPath(conf, plugin), formatVersionStringForFS(version))","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/asdf-vm/asdf/blob/074a1722ca88d6677f228541ce06efaf4f9924d4/internal/installtest/installtest.go#L33-L69","documentation":"asdf's InstallOneVersion runs the plugin's optional 'download' callback in a temporary download directory. The download callback exists but returned a non-zero exit or the spawned command failed, and the failure was NOT a plugins.NoCallbackError (which is intentionally tolerated since the callback is optional). asdf wraps the underlying error so the plugin author's failure surfaces during installation testing.","triggerScenarios":"Calling InstallOneVersion (used by `asdf install` and plugin test tooling) when: the plugin defines a download callback that exits non-zero; the callback script itself crashes (bad interpreter, syntax error); or RunCallback fails for a non-NoCallbackError reason such as the callback file not being executable or the fork/exec failing.","commonSituations":"Plugin authors shipping a broken download script; callback referencing missing environment variables or tools (curl, git) not present on the machine; restrictive permissions making the callback non-executable; users installing a plugin whose download URL is dead or behind an auth wall.","solutions":["Inspect the wrapped error and the plugin's download callback script; run it manually to reproduce the failure.","Fix the plugin's download callback (missing dependency, bad URL, wrong shebang, non-zero exit).","Ensure required tools/env vars the callback relies on are available in the install environment.","If the callback should be optional/absent, remove it entirely so NoCallbackError applies and is skipped."],"exampleFix":"// plugin lib/utils.bash download callback failing\n# before\ncurl -sSL \"$release_url\" | tar xz\n# after (check failure and give a clear message)\ncurl --fail -sSL \"$release_url\" -o /tmp/pkg.tar.gz || exit 1\nmkdir -p \"$ASDF_DOWNLOAD_PATH\"\ntar xzf /tmp/pkg.tar.gz -C \"$ASDF_DOWNLOAD_PATH\" --strip-components=1","handlingStrategy":"type-guard","validationCode":"if _, err := os.Stat(filepath.Join(pluginDir, \"lib\", \"utils.bash\")); err == nil {\n    // plugin defines callbacks; ensure deps like curl/git exist\n    if _, err := exec.LookPath(\"git\"); err != nil {\n        return fmt.Errorf(\"download callback needs git: %w\", err)\n    }\n}","typeGuard":"var nce plugins.NoCallbackError\nif errors.As(err, &nce) {\n    // optional callback absent — tolerate\n} else if err != nil {\n    return fmt.Errorf(\"download failed: %w\", err)\n}","tryCatchPattern":"if err := installtest.InstallOneVersion(conf, plugin, version); err != nil {\n    var nce plugins.NoCallbackError\n    if errors.As(err, &nce) {\n        // tolerated: callback missing\n    } else {\n        log.Printf(\"download callback failed: %v\", err)\n    }\n}","preventionTips":["Run the plugin's download callback manually in a scratch dir before installing.","Ensure curl/git and other callback dependencies are installed in CI images.","Keep callbacks' error output visible (capture stdOut/stdErr) for diagnosis.","Pin plugin versions tested with your asdf version."],"tags":["plugin-callback","install","download"],"backgroundTag":"plugin-download-callback-failed","analyzedSha":"074a1722ca88d6677f228541ce06efaf4f9924d4","analyzedAt":"2026-08-30T19:56:42.972Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}