router-for-me/CLIProxyAPI · error

direct install plugin %q version %q resolved as %q

Error message

direct install plugin %q version %q resolved as %q

What it means

Returned from directPluginVersion when the requested version matches one of the plugin's historical entries in plugin.Versions, but that candidate's install plan (after NormalizeInstallPlan, with empty type defaulted to direct) resolves to a non-direct install type. Per-version install metadata overrides the plugin-level type, and a non-direct candidate cannot be used for direct install.

Source

Thrown at internal/pluginstore/install.go:233

		plugin.Version = version
		plugin.Install = NormalizeInstallPlan(plugin.Install)
		plugin.Install.Type = InstallTypeDirect
		if errPlan := ValidateInstallPlan(plugin.Install); errPlan != nil {
			return Plugin{}, fmt.Errorf("direct install plugin %q version %q: %w", id, version, errPlan)
		}
		return plugin, nil
	}
	for _, candidate := range plugin.Versions {
		if normalizeVersion(candidate.Version) != version {
			continue
		}
		plugin.Version = version
		plugin.Install = NormalizeInstallPlan(candidate.Install)
		if plugin.Install.Type == "" {
			plugin.Install.Type = InstallTypeDirect
		}
		if plugin.Install.Type != InstallTypeDirect {
			return Plugin{}, fmt.Errorf("direct install plugin %q version %q resolved as %q", id, version, plugin.Install.Type)
		}
		if errPlan := ValidateInstallPlan(plugin.Install); errPlan != nil {
			return Plugin{}, fmt.Errorf("direct install plugin %q version %q: %w", id, version, errPlan)
		}
		return plugin, nil
	}
	return Plugin{}, fmt.Errorf("direct install plugin %q version %q not found in source", id, version)
}

func InstallArchive(archiveData []byte, plugin Plugin, options InstallOptions) (InstallResult, error) {
	options = normalizeInstallOptions(options)
	id := strings.TrimSpace(plugin.ID)
	if !validPluginID(id) {
		return InstallResult{}, fmt.Errorf("invalid plugin id %q", plugin.ID)
	}
	version := normalizeVersion(plugin.Version)
	if !validPluginVersion(version) {
		return InstallResult{}, fmt.Errorf("invalid plugin version %q", plugin.Version)

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Request a version whose registry entry is published with direct install type
  2. Update the registry's version entry to install type "direct" with direct artifacts
  3. Use the install API matching that version's published type

Example fix

// before
manifest.Version = "0.9.0" // registry: versions[0.9.0].install.type = "github-release"
plugin, err := client.ResolveDirect(ctx, manifest)

// after
manifest.Version = "1.0.0" // direct-type version
plugin, err := client.ResolveDirect(ctx, manifest)
Defensive patterns

Strategy: validation

Validate before calling

func versionIsDirectType(plugin pluginstore.Plugin, version string) bool {
    v := strings.TrimPrefix(strings.TrimPrefix(strings.TrimSpace(version), "v"), "V")
    for _, cand := range plugin.Versions {
        if strings.TrimPrefix(strings.TrimSpace(cand.Version), "v") == v {
            return pluginstore.PluginInstallType(pluginstore.Plugin{Install: cand.Install}) == pluginstore.InstallTypeDirect || strings.TrimSpace(string(cand.Install.Type)) == ""
        }
    }
    return false
}

Type guard

func isVersionTypeMismatch(err error) bool {
    return err != nil && strings.Contains(err.Error(), "version") && strings.Contains(err.Error(), "resolved as")
}

Try / catch

if err != nil {
    if isVersionTypeMismatch(err) {
        // pick another version or the matching install path
    }
}

Prevention

When it happens

Trigger: Requested version found only in plugin.Versions with install.type explicitly set to "github-release" (or another type) while the caller asked for direct install; mixed-type version history in the registry.

Common situations: Older versions of a plugin published via GitHub releases while newer ones are direct; registry migration that left legacy version entries with the old install type; requesting a pinned legacy version from a plugin that has since moved to direct distribution.

Related errors


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/e62a623a9b45c323. Report an issue: GitHub.