{"record":{"id":"053a6109b8812735","repo":"asdf-vm/asdf","slug":"unable-to-check-if-plugin-exists-w","errorCode":null,"errorMessage":"unable to check if plugin exists: %w","messagePattern":"unable to check if plugin exists: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/plugins/plugins.go","lineNumber":439,"sourceCode":"\t// Run post hooks\n\thook.Run(config, \"post_asdf_plugin_add\", []string{plugin.Name})\n\thook.Run(config, fmt.Sprintf(\"post_asdf_plugin_add_%s\", plugin.Name), []string{})\n\n\treturn nil\n}\n\n// Remove uninstalls a plugin by removing it from the file system if installed\nfunc Remove(config config.Config, pluginName string, stdout, stderr io.Writer) error {\n\terr := validatePluginName(pluginName)\n\tif err != nil {\n\t\treturn err\n\t}\n\n\tplugin := New(config, pluginName)\n\n\texists, err := PluginExists(config.DataDir, pluginName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to check if plugin exists: %w\", err)\n\t}\n\n\tif !exists {\n\t\treturn fmt.Errorf(\"No such plugin: %s\", pluginName)\n\t}\n\n\thook.Run(config, \"pre_asdf_plugin_remove\", []string{plugin.Name})\n\thook.Run(config, fmt.Sprintf(\"pre_asdf_plugin_remove_%s\", plugin.Name), []string{})\n\n\tenv := map[string]string{\n\t\t\"ASDF_PLUGIN_PATH\":       plugin.Dir,\n\t\t\"ASDF_PLUGIN_SOURCE_URL\": plugin.URL,\n\t}\n\tplugin.RunCallback(\"pre-plugin-remove\", []string{}, env, stdout, stderr)\n\n\tpluginDir := data.PluginDirectory(config.DataDir, pluginName)\n\tdownloadDir := data.DownloadDirectory(config.DataDir, pluginName)\n\tinstallDir := data.InstallDirectory(config.DataDir, pluginName)","sourceCodeStart":421,"sourceCodeEnd":457,"githubUrl":"https://github.com/asdf-vm/asdf/blob/074a1722ca88d6677f228541ce06efaf4f9924d4/internal/plugins/plugins.go#L421-L457","documentation":"Remove first calls PluginExists, which stats the plugin's directory under the data dir. If that stat fails with an error other than ErrNotExist (e.g. a permission problem on a parent directory), the error is wrapped with this message rather than treated as 'not installed'. It distinguishes 'could not inspect' from 'definitely missing'.","triggerScenarios":"plugins.Remove when the os.Stat on data.PluginDirectory(dataDir, pluginName) fails with a non-ENOENT error (permissions, I/O error, path is weird).","commonSituations":"Running asdf without read permission on ASDF_DATA_DIR or the plugins directory, NFS/permission issues after switching users, or a data dir path that is a file instead of a directory.","solutions":["Check permissions on ASDF_DATA_DIR (~/.asdf) and its plugins/ directory; fix with chmod/chown","Verify ASDF_DATA_DIR points to a real, accessible directory","Retry the remove after fixing filesystem access"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"info, err := os.Stat(data.PluginDirectory(dataDir, name))\nif err != nil && !errors.Is(err, fs.ErrNotExist) {\n    return fmt.Errorf(\"cannot inspect plugin dir: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"unable to check if plugin exists\") {\n    // handle filesystem access problem before retrying Remove\n}","preventionTips":["Keep ASDF_DATA_DIR readable by the user running asdf","Avoid running asdf with mismatched user identities on shared data dirs"],"tags":["filesystem","permissions","asdf"],"backgroundTag":"filesystem-permission-denied","analyzedSha":"074a1722ca88d6677f228541ce06efaf4f9924d4","analyzedAt":"2026-08-30T19:56:42.972Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}