asdf-vm/asdf · error

unable to check if plugin already exists: %w

Error message

unable to check if plugin already exists: %w

What it means

Plugin.Add checks PluginExists(dataDir, pluginName) before cloning; if that check itself returns an error, it is wrapped as 'unable to check if plugin already exists'. The add operation aborts because asdf cannot safely determine whether the plugin is already installed — usually a filesystem/stat problem on the data dir.

Source

Thrown at internal/plugins/plugins.go:369

				})
			}
		}
	}

	return plugins, nil
}

// Add takes plugin name and Git URL and installs the plugin if it isn't
// already installed
func Add(config config.Config, pluginName, pluginURL, ref string) error {
	err := validatePluginName(pluginName)
	if err != nil {
		return err
	}

	exists, err := PluginExists(config.DataDir, pluginName)
	if err != nil {
		return fmt.Errorf("unable to check if plugin already exists: %w", err)
	}

	if exists {
		return NewPluginAlreadyExists(pluginName)
	}

	plugin := New(config, pluginName)

	if pluginURL == "" {
		// Ignore error here as the default value is fine
		disablePluginIndex, _ := config.DisablePluginShortNameRepository()

		if disablePluginIndex {
			return fmt.Errorf("Short-name plugin repository is disabled")
		}

		lastCheckDuration := 0
		// We don't care about errors here as we can use the default value

View on GitHub (pinned to 074a1722ca)

Solutions

  1. Inspect the wrapped underlying error — it names the actual OS failure (path, errno).
  2. Fix permissions/ownership on the data dir (mkdir -p, chown -R).
  3. Verify ASDF_DATA_DIR points to a valid, accessible directory.
  4. Remove any regular file occupying a path component that should be a directory.

Example fix

// before: parent path is a file
~/.asdf/plugins exists as a regular file
# Error: unable to check if plugin already exists: ...
// after
rm "$HOME/.asdf/plugins"   # remove the offending file
mkdir -p "$HOME/.asdf/plugins"
Defensive patterns

Strategy: validation

Validate before calling

dataDir := conf.DataDir
if fi, err := os.Stat(dataDir); err != nil || !fi.IsDir() {
    if err := os.MkdirAll(dataDir, 0o755); err != nil {
        return fmt.Errorf("data dir unusable: %w", err)
    }
}
// probe writability of plugins path before Add
probe := filepath.Join(dataDir, "plugins", ".probe")
os.MkdirAll(filepath.Dir(probe), 0o755)
if err := os.WriteFile(probe, nil, 0o644); err != nil {
    return err
}
os.Remove(probe)

Try / catch

if err := plugins.Add(conf, pluginName, repoURL); err != nil {
    if strings.Contains(err.Error(), "unable to check if plugin already exists") {
        log.Printf("fix data dir access (%s): %v", conf.DataDir, err)
    }
}

Prevention

When it happens

Trigger: Calling Add (or `asdf plugin add <name>`) when PluginExists fails: the data dir path is inaccessible (permission denied on a parent directory); a component of the path is a file, not a directory; the path is too long or contains invalid characters; underlying OS stat errors (e.g. I/O error, network mount down).

Common situations: ASDF_DATA_DIR pointing at an unavailable NFS/SMB mount; root-owned ~/.asdf making stat of children fail for the user; corrupted data dir where the plugin path's parent is a regular file; sandboxed CI denying filesystem access.

Related errors


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