{"record":{"id":"e400c9b8331b0d03","repo":"asdf-vm/asdf","slug":"unable-to-list-plugins-w","errorCode":null,"errorMessage":"unable to list plugins: %w","messagePattern":"unable to list plugins: %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/versions/versions.go","lineNumber":72,"sourceCode":"// VersionAlreadyInstalledError is returned whenever a version is already\n// installed.\ntype VersionAlreadyInstalledError struct {\n\ttoolName string\n\tversion  toolversions.Version\n}\n\nfunc (e VersionAlreadyInstalledError) Error() string {\n\treturn fmt.Sprintf(\"version %s of %s is already installed\", e.version.Value, e.toolName)\n}\n\n// InstallAll installs all specified versions of every tool for the current\n// directory. Typically this will just be a single version, if not already\n// installed, but it may be multiple versions if multiple versions for the tool\n// are specified in the .tool-versions file.\nfunc InstallAll(conf config.Config, dir string, stdOut io.Writer, stdErr io.Writer) (failures []error) {\n\tplugins, err := plugins.List(conf, false, false)\n\tif err != nil {\n\t\treturn []error{fmt.Errorf(\"unable to list plugins: %w\", err)}\n\t}\n\n\t// Ideally we should install these in the order they are specified in the\n\t// closest .tool-versions file, but for now that is too complicated to\n\t// implement.\n\tfor _, plugin := range plugins {\n\t\terr := Install(conf, plugin, dir, stdOut, stdErr)\n\t\tif err != nil {\n\t\t\tfailures = append(failures, err)\n\t\t}\n\t}\n\n\treturn failures\n}\n\n// Install installs all specified versions of a tool for the current directory.\n// Typically this will just be a single version, if not already installed, but\n// it may be multiple versions if multiple versions for the tool are specified","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/asdf-vm/asdf/blob/074a1722ca88d6677f228541ce06efaf4f9924d4/internal/versions/versions.go#L54-L90","documentation":"InstallAll first enumerates installed plugins via plugins.List. If listing fails (usually filesystem access problems on the plugins directory, since List walks plugin dirs and reads their metadata), InstallAll aborts immediately, returning this single wrapped error instead of attempting installs. The %w wrap preserves the underlying cause for errors.Is/As inspection.","triggerScenarios":"Calling versions.InstallAll when plugins.List returns an error — e.g. the plugins directory under conf.DataDir is unreadable, or a plugin's repo is in a state List cannot handle.","commonSituations":"Corrupted or permission-denied ~/.asdf/plugins directory, ASDF_DATA_DIR misconfigured, partial plugin directory left by an interrupted add.","solutions":["Inspect the wrapped cause (errors.Unwrap / printed chain) to find the filesystem problem","Fix permissions on the plugins directory under ASDF_DATA_DIR","Remove/re-add the broken plugin directory that breaks List","Run `asdf plugin list` to see whether listing works at all"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if _, err := plugins.List(conf, false, false); err != nil {\n    return fmt.Errorf(\"plugins dir unusable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"failures := versions.InstallAll(conf, dir, stdOut, stdErr)\nfor _, err := range failures {\n    if strings.Contains(err.Error(), \"unable to list plugins\") {\n        // fix data dir access before any installs\n    }\n}","preventionTips":["Verify plugins dir permissions after changing ASDF_DATA_DIR","Run `asdf plugin list` as a smoke check in CI setup"],"tags":["plugin-management","filesystem","install"],"backgroundTag":"plugin-list-failed","analyzedSha":"074a1722ca88d6677f228541ce06efaf4f9924d4","analyzedAt":"2026-08-30T19:56:42.972Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}