coreybutler/nvm-windows · error
error: failed to download asset: %v
Error message
error: failed to download asset: %v
What it means
During upgrade, each extra entry in update.Assets (e.g. update.exe) is fetched with get(). This error means one of those per-asset downloads failed. Note the loop sends the error to the status channel but does not break or return, so the upgrade continues with a missing asset unless the consumer aborts — the missing file surfaces later as a copy or exec failure.
Source
Thrown at src/upgrade/upgrade.go:443
status <- Status{Text: "extracting update..."}
if err := unzip(filepath.Join(tmp, "assets.zip"), filepath.Join(tmp, "assets")); err != nil {
status <- Status{Err: err}
}
// Get any additional assets
if len(update.Assets) > 0 {
status <- Status{Text: fmt.Sprintf("downloading %d additional assets...", len(update.Assets))}
for _, asset := range update.Assets {
var assetURL string
if !strings.HasPrefix(asset, "http") {
assetURL = update.SourceURL
// assetURL = fmt.Sprintf(update.SourceURL, asset)
} else {
assetURL = asset
}
assetBody, err := get(assetURL)
if err != nil {
status <- Status{Err: fmt.Errorf("error: failed to download asset: %v\n", err)}
}
assetPath := filepath.Join(tmp, "assets", asset)
os.WriteFile(assetPath, assetBody, os.ModePerm)
}
}
// Debugging
if verbose {
tree(tmp, "downloaded files (extracted):")
nvmtestcmd := exec.Command(filepath.Join(tmp, "assets", "nvm.exe"), "version")
nvmtestcmd.Stdout = os.Stdout
nvmtestcmd.Stderr = os.Stderr
err = nvmtestcmd.Run()
if err != nil {
fmt.Println("error running nvm.exe:", err)
}
}View on GitHub (pinned to 5b18223ca1)
Solutions
- Identify which asset failed (enable verbose/debug logging) and fetch its URL manually to see the status code.
- Retry the upgrade — transient failures on the small asset downloads are common.
- Check proxy rules cover every host in the release manifest, not just the main download host.
- Fix the release manifest if the asset name/URL is genuinely wrong upstream.
Example fix
// before
assetBody, err := get(assetURL)
if err != nil {
status <- Status{Err: fmt.Errorf("error: failed to download asset: %v\n", err)}
}
// after: abort the loop on failure so the upgrade does not continue with missing files
assetBody, err := get(assetURL)
if err != nil {
status <- Status{Err: fmt.Errorf("error: failed to download asset %s: %v\n", assetURL, err)}
return err
} Defensive patterns
Strategy: validation
Validate before calling
// Resolve and validate every asset URL before the upgrade starts
for _, asset := range update.Assets {
u := asset
if !strings.HasPrefix(u, "http") {
u = update.SourceURL
}
if resp, err := http.Head(u); err != nil || resp.StatusCode != http.StatusOK {
return fmt.Errorf("asset not fetchable: %s", u)
}
} Try / catch
On any asset download error, abort the whole upgrade (return) — continuing leaves a half-updated tree. Distinguish 404 (manifest broken upstream) from transport errors (retry) in the message.
Prevention
- Ensure proxy rules cover every host referenced by the release manifest.
- Pre-validate asset URLs when authoring release manifests.
When it happens
Trigger: Asset URLs listed in the release manifest that 404 (renamed asset); non-http asset names resolved against update.SourceURL that produce an invalid URL; network drop mid-loop after the main zip succeeded; proxy allowing the zip host but blocking the asset host.
Common situations: GitHub release edited between publishing the manifest and assets; mixed hosts where update.exe sits on a CDN the firewall blocks; transient failure on the Nth of several sequential downloads.
Related errors
- error: failed to download new version: %v
- error: failed to download checksum: %v
- failed to download v%v arm 64-bit executable
- Failed to extract npm: %v
- Could not download npm for node v%s. Please visit %s to down
AI-assisted analysis of coreybutler/nvm-windows@5b18223ca1 (2026-08-15).
Data as JSON: /api/errors/c07fdddb7b664b63.
Report an issue: GitHub.