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 base

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Fetch a release first and use ManifestFromRelease(source, plugin, release)
  2. If you want 'latest', call Client.FetchLatestRelease then ManifestFromRelease
  3. 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

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


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