{"record":{"id":"c07fdddb7b664b63","repo":"coreybutler/nvm-windows","slug":"error-failed-to-download-asset-v","errorCode":null,"errorMessage":"error: failed to download asset: %v\n","messagePattern":"error: failed to download asset: (.+?)\n","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/upgrade/upgrade.go","lineNumber":443,"sourceCode":"\tstatus <- Status{Text: \"extracting update...\"}\n\tif err := unzip(filepath.Join(tmp, \"assets.zip\"), filepath.Join(tmp, \"assets\")); err != nil {\n\t\tstatus <- Status{Err: err}\n\t}\n\n\t// Get any additional assets\n\tif len(update.Assets) > 0 {\n\t\tstatus <- Status{Text: fmt.Sprintf(\"downloading %d additional assets...\", len(update.Assets))}\n\t\tfor _, asset := range update.Assets {\n\t\t\tvar assetURL string\n\t\t\tif !strings.HasPrefix(asset, \"http\") {\n\t\t\t\tassetURL = update.SourceURL\n\t\t\t\t// assetURL = fmt.Sprintf(update.SourceURL, asset)\n\t\t\t} else {\n\t\t\t\tassetURL = asset\n\t\t\t}\n\t\t\tassetBody, err := get(assetURL)\n\t\t\tif err != nil {\n\t\t\t\tstatus <- Status{Err: fmt.Errorf(\"error: failed to download asset: %v\\n\", err)}\n\t\t\t}\n\n\t\t\tassetPath := filepath.Join(tmp, \"assets\", asset)\n\t\t\tos.WriteFile(assetPath, assetBody, os.ModePerm)\n\t\t}\n\t}\n\n\t// Debugging\n\tif verbose {\n\t\ttree(tmp, \"downloaded files (extracted):\")\n\t\tnvmtestcmd := exec.Command(filepath.Join(tmp, \"assets\", \"nvm.exe\"), \"version\")\n\t\tnvmtestcmd.Stdout = os.Stdout\n\t\tnvmtestcmd.Stderr = os.Stderr\n\t\terr = nvmtestcmd.Run()\n\t\tif err != nil {\n\t\t\tfmt.Println(\"error running nvm.exe:\", err)\n\t\t}\n\t}","sourceCodeStart":425,"sourceCodeEnd":461,"githubUrl":"https://github.com/coreybutler/nvm-windows/blob/5b18223ca19ff50d707f35410dbc6bd440a9f74d/src/upgrade/upgrade.go#L425-L461","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nassetBody, err := get(assetURL)\nif err != nil {\n    status <- Status{Err: fmt.Errorf(\"error: failed to download asset: %v\\n\", err)}\n}\n\n// after: abort the loop on failure so the upgrade does not continue with missing files\nassetBody, err := get(assetURL)\nif err != nil {\n    status <- Status{Err: fmt.Errorf(\"error: failed to download asset %s: %v\\n\", assetURL, err)}\n    return err\n}","handlingStrategy":"validation","validationCode":"// Resolve and validate every asset URL before the upgrade starts\nfor _, asset := range update.Assets {\n    u := asset\n    if !strings.HasPrefix(u, \"http\") {\n        u = update.SourceURL\n    }\n    if resp, err := http.Head(u); err != nil || resp.StatusCode != http.StatusOK {\n        return fmt.Errorf(\"asset not fetchable: %s\", u)\n    }\n}","typeGuard":null,"tryCatchPattern":"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.","preventionTips":["Ensure proxy rules cover every host referenced by the release manifest.","Pre-validate asset URLs when authoring release manifests."],"tags":["network","upgrade","assets","nvm-windows"],"backgroundTag":null,"analyzedSha":"5b18223ca19ff50d707f35410dbc6bd440a9f74d","analyzedAt":"2026-08-15T10:06:51.428Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}