router-for-me/CLIProxyAPI · error
fetch direct install source: %w
Error message
fetch direct install source: %w
What it means
Wrapped error returned when sourceClient.FetchRegistry(ctx) fails during direct-install resolution. The client re-points its RegistryURL at the resolved source (manifest.SourceURL or the client's own RegistryURL) and fetches the plugin registry document from it; any HTTP, parsing, or network failure at that step surfaces here with the cause preserved via %w.
Source
Thrown at internal/pluginstore/install.go:199
plugin := manifest.Plugin()
plugin.Version = normalizeVersion(manifest.Version)
plugin.Install = NormalizeInstallPlan(plugin.Install)
plugin.Install.Type = InstallTypeDirect
if len(plugin.Install.Artifacts) > 0 {
return plugin, nil
}
sourceURL := strings.TrimSpace(manifest.SourceURL)
if sourceURL == "" {
sourceURL = strings.TrimSpace(c.RegistryURL)
}
if sourceURL == "" {
return Plugin{}, fmt.Errorf("direct install manifest missing source-url")
}
sourceClient := c
sourceClient.RegistryURL = sourceURL
registry, errRegistry := sourceClient.FetchRegistry(ctx)
if errRegistry != nil {
return Plugin{}, fmt.Errorf("fetch direct install source: %w", errRegistry)
}
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 = InstallTypeDirectView on GitHub (pinned to 78f0c4079e)
Solutions
- curl the registry URL (sourceURL + registry document path) to confirm it returns valid JSON with HTTP 200
- Fix scheme/host typos in manifest.SourceURL or Client.RegistryURL
- If the registry requires auth or custom headers, configure them on the Client's HTTP transport before installing
- Retry with backoff for transient 5xx/network failures
Example fix
// before
manifest.SourceURL = "https://plugins.example" // wrong host, FetchRegistry fails
// after
manifest.SourceURL = "https://plugins.example.com/registry.json"
plugin, err := client.ResolveDirect(ctx, manifest)
if err != nil {
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// retry with backoff
}
} Defensive patterns
Strategy: retry
Validate before calling
func registryFetchable(ctx context.Context, registryURL string) error {
resp, err := http.Get(registryURL) //nolint:noctx // preflight only
if err != nil {
return fmt.Errorf("registry unreachable: %w", err)
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("registry returned %d", resp.StatusCode)
}
return nil
} Type guard
func isFetchRegistryError(err error) bool {
return err != nil && strings.Contains(err.Error(), "fetch direct install source:")
} Try / catch
if err != nil {
if isFetchRegistryError(err) {
var netErr net.Error
if errors.As(err, &netErr) || errors.Is(err, context.DeadlineExceeded) {
// transient: retry with backoff
} else {
// permanent: log registryURL and alert
}
}
} Prevention
- Preflight the registry URL with a GET and JSON-decode check
- Cache the last good registry document as a fallback source
- Monitor registry reachability from the environment that runs installs
When it happens
Trigger: Direct manifest install where the source URL is unreachable, returns a non-2xx status, serves malformed registry JSON, requires auth that was not provided, or when DNS/TLS fails for the registry host.
Common situations: SourceURL with a typo or wrong scheme; self-hosted registry temporarily down; registry behind auth (401/403) while the client sends no credentials; CDN serving an HTML error page instead of JSON; certificate mismatch for private registries.
Related errors
- direct install plugin %q not found in source
- direct install plugin %q resolved as %q
- download artifact: %w
- direct install manifest missing source-url
- direct install plugin %q version %q: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/16131a604e5f200e.
Report an issue: GitHub.