router-for-me/CLIProxyAPI · error
download artifact: %w
Error message
download artifact: %w
What it means
Wrapped error returned by Client.InstallDirect when c.DownloadArtifact(ctx, artifact) fails. The artifact was successfully selected from the install plan (matching GOOS/GOARCH), but the HTTP fetch of the artifact bytes failed. The underlying error (network failure, DNS error, HTTP 4xx/5xx, TLS problem) is preserved via %w so callers can inspect it with errors.Is/errors.As.
Source
Thrown at internal/pluginstore/install.go:167
if !validPluginID(plugin.ID) {
return InstallResult{}, fmt.Errorf("invalid plugin id %q", plugin.ID)
}
if !validPluginVersion(plugin.Version) {
return InstallResult{}, fmt.Errorf("invalid plugin version %q", plugin.Version)
}
plan = NormalizeInstallPlan(plan)
plan.Type = InstallTypeDirect
if errValidate := ValidateInstallPlan(plan); errValidate != nil {
return InstallResult{}, errValidate
}
options = normalizeInstallOptions(options)
artifact, errSelect := SelectArtifact(plan, options.GOOS, options.GOARCH)
if errSelect != nil {
return InstallResult{}, errSelect
}
archiveData, errDownload := c.DownloadArtifact(ctx, artifact)
if errDownload != nil {
return InstallResult{}, fmt.Errorf("download artifact: %w", errDownload)
}
if errVerify := VerifyArtifactChecksum(artifact, archiveData); errVerify != nil {
return InstallResult{}, errVerify
}
result, errInstall := InstallArchive(archiveData, plugin, options)
if errInstall != nil {
return InstallResult{}, errInstall
}
result.InstallType = InstallTypeDirect
return result, nil
}
func (c Client) directPluginFromManifest(ctx context.Context, manifest Manifest) (Plugin, error) {
plugin := manifest.Plugin()
plugin.Version = normalizeVersion(manifest.Version)
plugin.Install = NormalizeInstallPlan(plugin.Install)
plugin.Install.Type = InstallTypeDirect
if len(plugin.Install.Artifacts) > 0 {View on GitHub (pinned to 78f0c4079e)
Solutions
- Inspect the wrapped error (errors.Unwrap / %w chain) to identify the real cause: HTTP status, DNS, or timeout
- Verify the artifact URL from the install plan resolves in curl before retrying
- Retry with backoff for transient network failures; re-fetch the registry first if signed URLs may have expired
- Check proxy/firewall/egress rules for the artifact host
Example fix
result, err := client.InstallDirect(ctx, plugin, plan, options)
if err != nil {
if strings.Contains(err.Error(), "download artifact:") {
var urlErr *url.Error
if errors.As(err, &urlErr) {
log.Errorf("network failure downloading artifact: %v", urlErr)
}
}
}
// with retry for transient failures:
var result pluginstore.InstallResult
err := retry(3, time.Second, func() error {
var e error
result, e = client.InstallDirect(ctx, plugin, plan, options)
if e != nil && strings.Contains(e.Error(), "download artifact:") {
return e // retryable
}
if e != nil {
return retry.Stop(e) // not retryable
}
return nil
}) Defensive patterns
Strategy: retry
Validate before calling
func artifactReachable(ctx context.Context, artifactURL string) error {
req, _ := http.NewRequestWithContext(ctx, http.MethodHead, artifactURL, nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer func() { _ = resp.Body.Close() }()
if resp.StatusCode >= 400 {
return fmt.Errorf("artifact URL returned %d", resp.StatusCode)
}
return nil
} Type guard
func isDownloadArtifactError(err error) bool {
return err != nil && strings.Contains(err.Error(), "download artifact:")
} Try / catch
var result pluginstore.InstallResult
err := installWithBackoff(ctx, client, plugin, plan, options, &result, 3)
func installWithBackoff(...) error {
for attempt := 0; attempt < 3; attempt++ {
r, e := client.InstallDirect(ctx, plugin, plan, options)
if e == nil { *out = r; return nil }
if !isDownloadArtifactError(e) { return e } // only retry network step
var netErr net.Error
if !errors.As(e, &netErr) { return e } // non-network cause: stop
time.Sleep(time.Duration(attempt+1) * time.Second)
}
return errors.New("download artifact: exhausted retries")
} Prevention
- HEAD-check artifact URLs before starting an install batch
- Re-fetch the registry before retrying when signed/expiring URLs are in play
- Wrap installs in bounded retry with backoff for transient network errors only
When it happens
Trigger: InstallDirect with an install plan whose artifact URLs point to a host that is unreachable, returns 404/403, has an expired signed URL, or when the machine has no network egress; also triggered by a proxy or firewall blocking the artifact host, or the server closing the connection mid-download.
Common situations: CI runners without outbound network access; artifact URLs from a stale registry snapshot whose CDN links expired; corporate proxies intercepting TLS; transient network flakiness during long downloads; wrong RegistryURL pointing at a host that serves HTML error pages.
Related errors
- download %s: %w
- download checksums.txt: %w
- response exceeds maximum allowed size of %d bytes
- fetch direct install source: %w
- stat target plugin: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/4f4ffb4742a1683b.
Report an issue: GitHub.