router-for-me/CLIProxyAPI · error
direct install plugin %q version %q: %w
Error message
direct install plugin %q version %q: %w
What it means
Wrapped error from directPluginVersion when the resolved plugin's TOP-LEVEL version exactly matches the requested version (normalizeVersion(plugin.Version) == version), so its Install plan is used directly, but ValidateInstallPlan rejects that plan. The id and requested version are included; the underlying validation failure (e.g. invalid/missing artifact entries) is chained via %w.
Source
Thrown at internal/pluginstore/install.go:219
resolved, okPlugin := registry.PluginByID(manifest.ID)
if !okPlugin {
return Plugin{}, fmt.Errorf("direct install plugin %q not found in source", strings.TrimSpace(manifest.ID))
}
if PluginInstallType(resolved) != InstallTypeDirect {
return Plugin{}, fmt.Errorf("direct install plugin %q resolved as %q", strings.TrimSpace(manifest.ID), PluginInstallType(resolved))
}
return directPluginVersion(resolved, manifest.ID, manifest.Version)
}
func directPluginVersion(plugin Plugin, id string, version string) (Plugin, error) {
id = strings.TrimSpace(id)
version = normalizeVersion(version)
if normalizeVersion(plugin.Version) == version {
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)
}View on GitHub (pinned to 78f0c4079e)
Solutions
- Unwrap the error and read the ValidateInstallPlan message to see which plan field is invalid
- Fix the registry entry for that plugin/version: ensure the install plan has at least one well-formed artifact (URL + checksum) for the target platform
- If the registry is remote, re-fetch it to rule out a stale cached copy
Example fix
// before: registry entry
// { "id": "p", "version": "1.0.0", "install": { "type": "direct", "artifacts": [] } }
plugin, err := client.ResolveDirect(ctx, manifest) // "direct install plugin \"p\" version \"1.0.0\": ..."
// after
// { "id": "p", "version": "1.0.0", "install": { "type": "direct", "artifacts": [
// { "url": "https://cdn.example.com/p-1.0.0-linux-amd64.zip", "checksum": "sha256:...", "os": "linux", "arch": "amd64" } ] } } Defensive patterns
Strategy: try-catch
Try / catch
plugin, err := client.ResolveDirect(ctx, manifest)
if err != nil {
if strings.Contains(err.Error(), fmt.Sprintf("direct install plugin %q version %q:", manifest.ID, manifest.Version)) {
cause := errors.Unwrap(err) // ValidateInstallPlan detail
return fmt.Errorf("registry install plan invalid for %s@%s: %w", manifest.ID, manifest.Version, cause)
}
return err
} Prevention
- Validate registry entries with a CI check that runs ValidateInstallPlan-equivalent rules on every publish
- Require at least one artifact per target platform in the plan before publishing a version
- Unwrap chained errors in logs so the real plan defect is visible
When it happens
Trigger: Registry entry whose top-level version matches the requested one but whose install plan is invalid: zero usable artifacts, malformed artifact URLs, missing checksums, or an invalid plan type after NormalizeInstallPlan + forced InstallTypeDirect.
Common situations: Registry published with an incomplete artifacts list for the current version; artifact entries filtered out because they lack URLs; registry hand-edited and plan fields left blank; schema change in the registry format leaving plan fields unparsed.
Related errors
- install type %q is not direct
- direct plugin sync manifest requires pinned artifacts
- fetch direct install source: %w
- direct install plugin %q not found in source
- direct install plugin %q resolved as %q
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/fe36f9782605c7e5.
Report an issue: GitHub.