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

  1. Inspect the wrapped error (errors.Unwrap / %w chain) to identify the real cause: HTTP status, DNS, or timeout
  2. Verify the artifact URL from the install plan resolves in curl before retrying
  3. Retry with backoff for transient network failures; re-fetch the registry first if signed URLs may have expired
  4. 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

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


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