{"record":{"id":"e80552b3a86e0504","repo":"router-for-me/CLIProxyAPI","slug":"direct-install-plugin-q-resolved-as-q","errorCode":null,"errorMessage":"direct install plugin %q resolved as %q","messagePattern":"direct install plugin %q resolved as %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/pluginstore/install.go","lineNumber":206,"sourceCode":"\tsourceURL := strings.TrimSpace(manifest.SourceURL)\n\tif sourceURL == \"\" {\n\t\tsourceURL = strings.TrimSpace(c.RegistryURL)\n\t}\n\tif sourceURL == \"\" {\n\t\treturn Plugin{}, fmt.Errorf(\"direct install manifest missing source-url\")\n\t}\n\tsourceClient := c\n\tsourceClient.RegistryURL = sourceURL\n\tregistry, errRegistry := sourceClient.FetchRegistry(ctx)\n\tif errRegistry != nil {\n\t\treturn Plugin{}, fmt.Errorf(\"fetch direct install source: %w\", errRegistry)\n\t}\n\tresolved, okPlugin := registry.PluginByID(manifest.ID)\n\tif !okPlugin {\n\t\treturn Plugin{}, fmt.Errorf(\"direct install plugin %q not found in source\", strings.TrimSpace(manifest.ID))\n\t}\n\tif PluginInstallType(resolved) != InstallTypeDirect {\n\t\treturn Plugin{}, fmt.Errorf(\"direct install plugin %q resolved as %q\", strings.TrimSpace(manifest.ID), PluginInstallType(resolved))\n\t}\n\treturn directPluginVersion(resolved, manifest.ID, manifest.Version)\n}\n\nfunc directPluginVersion(plugin Plugin, id string, version string) (Plugin, error) {\n\tid = strings.TrimSpace(id)\n\tversion = normalizeVersion(version)\n\tif normalizeVersion(plugin.Version) == version {\n\t\tplugin.Version = version\n\t\tplugin.Install = NormalizeInstallPlan(plugin.Install)\n\t\tplugin.Install.Type = InstallTypeDirect\n\t\tif errPlan := ValidateInstallPlan(plugin.Install); errPlan != nil {\n\t\t\treturn Plugin{}, fmt.Errorf(\"direct install plugin %q version %q: %w\", id, version, errPlan)\n\t\t}\n\t\treturn plugin, nil\n\t}\n\tfor _, candidate := range plugin.Versions {\n\t\tif normalizeVersion(candidate.Version) != version {","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/pluginstore/install.go#L188-L224","documentation":"Returned when the plugin IS found in the source registry but PluginInstallType(resolved) is not InstallTypeDirect — for example the registry entry is published as a github-release install. Direct install requires the source registry to also describe the plugin as direct-type so that artifact URLs can be resolved from the registry itself; a type mismatch means the resolution path is inconsistent with the requested install mode.","triggerScenarios":"Manifest requests direct install, source registry publishes the same plugin ID with install type \"github-release\" (or any non-direct type). Happens when a plugin switched distribution models, or when SourceURL points at a registry that re-publishes the plugin differently.","commonSituations":"Upstream plugin migrated from registry-hosted artifacts to GitHub releases while local manifests still request direct install; mixing staging registry (direct) with production registry (github-release); registry entry edited to change install type.","solutions":["Check the plugin's install type in the source registry and use the matching install API (e.g. the GitHub release install path instead of direct)","Update the source registry entry so the plugin is published with direct install type","Update manifest.SourceURL to the registry that publishes the plugin as direct-type"],"exampleFix":"// before: registry says install.type = \"github-release\"\nplugin, err := client.ResolveDirect(ctx, manifest) // \"resolved as \\\"github-release\\\"\"\n\n// after: use the install path matching the published type\nresult, err := client.InstallFromGitHubRelease(ctx, plugin, options) // or fix the registry entry to type \"direct\"","handlingStrategy":"validation","validationCode":"func pluginIsDirectType(ctx context.Context, c pluginstore.Client, id string) (bool, error) {\n    reg, err := c.FetchRegistry(ctx)\n    if err != nil {\n        return false, err\n    }\n    p, ok := reg.PluginByID(strings.TrimSpace(id))\n    if !ok {\n        return false, errors.New(\"plugin not in registry\")\n    }\n    return pluginstore.PluginInstallType(p) == pluginstore.InstallTypeDirect, nil\n}","typeGuard":"func isInstallTypeMismatch(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"resolved as\")\n}","tryCatchPattern":"if err != nil {\n    if isInstallTypeMismatch(err) {\n        // branch to the install API matching the published type\n    }\n}","preventionTips":["Publish one install type per plugin and keep it stable","Before requesting direct install, check PluginInstallType from the registry","Version-pin manifests to registries whose distribution model you control"],"tags":["go","plugin-store","registry","install-type","manifest"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}