router-for-me/CLIProxyAPI · error
github-release manifest requires a resolved release
Error message
github-release manifest requires a resolved release
What it means
Returned by ManifestFromPlugin (internal/pluginstore/manifest.go:56-57) when asked to build a manifest for a plugin whose install type is github-release. A github-release manifest carries fields (Version from the release, ReleaseTag) that only exist once a concrete release has been resolved from GitHub, so the un-resolved form is deliberately rejected rather than emitting an incomplete manifest.
Source
Thrown at internal/pluginstore/manifest.go:57
}
func ManifestFromPlugin(source Source, plugin Plugin) (Manifest, error) {
if errValidate := ValidatePlugin(plugin); errValidate != nil {
return Manifest{}, errValidate
}
switch PluginInstallType(plugin) {
case InstallTypeDirect:
manifest := manifestFromPlugin(source, plugin, Manifest{
SchemaVersion: SchemaVersionV2,
Version: strings.TrimSpace(plugin.Version),
Install: NormalizeInstallPlan(plugin.Install),
})
if errValidate := manifest.Validate(); errValidate != nil {
return Manifest{}, errValidate
}
return manifest, nil
case InstallTypeGitHubRelease:
return Manifest{}, fmt.Errorf("github-release manifest requires a resolved release")
default:
return Manifest{}, fmt.Errorf("unsupported install type %q", plugin.Install.Type)
}
}
func manifestFromPlugin(source Source, plugin Plugin, base Manifest) Manifest {
base.ID = strings.TrimSpace(plugin.ID)
base.Name = strings.TrimSpace(plugin.Name)
base.Description = strings.TrimSpace(plugin.Description)
base.Author = strings.TrimSpace(plugin.Author)
base.Logo = strings.TrimSpace(plugin.Logo)
base.Homepage = strings.TrimSpace(plugin.Homepage)
base.License = strings.TrimSpace(plugin.License)
base.Tags = append([]string(nil), plugin.Tags...)
base.SourceID = strings.TrimSpace(source.ID)
base.SourceName = strings.TrimSpace(source.Name)
base.SourceURL = strings.TrimSpace(source.URL)
return baseView on GitHub (pinned to 78f0c4079e)
Solutions
- Fetch a release first and use ManifestFromRelease(source, plugin, release)
- If you want 'latest', call Client.FetchLatestRelease then ManifestFromRelease
- Branch on PluginInstallType(plugin): direct -> ManifestFromPlugin, github-release -> ManifestFromRelease
Example fix
// before
m, err := pluginstore.ManifestFromPlugin(src, plugin) // panics-free but errors for github-release plugins
// after
release, err := client.FetchLatestRelease(ctx, plugin)
if err != nil { return err }
m, err := pluginstore.ManifestFromRelease(src, plugin, release) Defensive patterns
Strategy: type-guard
Type guard
func manifestBuildableWithoutRelease(p pluginstore.Plugin) bool {
return pluginstore.PluginInstallType(p) == pluginstore.InstallTypeDirect
} Prevention
- Branch on PluginInstallType before choosing ManifestFromPlugin vs ManifestFromRelease
- For github-release plugins, always fetch the release first (FetchLatestRelease or FetchReleaseByTag)
- Wrap manifest generation in a helper that dispatches per install type so call sites cannot pick the wrong constructor
When it happens
Trigger: Calling ManifestFromPlugin(source, plugin) where PluginInstallType(plugin) == "github-release" (explicitly set, or defaulted when Install.Type is empty). The correct entry point for this case is ManifestFromRelease, which takes the fetched Release and is invoked after FetchLatestRelease/FetchReleaseByTag.
Common situations: Registry-driven code iterating plugins and calling ManifestFromPlugin uniformly, forgetting that release-type plugins must go through FetchLatestRelease first; porting call sites from a version of the API where manifests did not distinguish install types.
Related errors
- missing required field release-tag
- release-tag %q resolves version %q, want %q
- plugin_manifest_failed
- unsupported install type %q
- missing required field version
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/f104fb528621aa69.
Report an issue: GitHub.