{"record":{"id":"4e8e181d234fcc18","repo":"coreybutler/nvm-windows","slug":"cannot-validate-update-file-checksum-mismatch","errorCode":null,"errorMessage":"cannot validate update file (checksum mismatch)","messagePattern":"cannot validate update file \\(checksum mismatch\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/upgrade/upgrade.go","lineNumber":422,"sourceCode":"\tfilePath := filepath.Join(tmp, \"assets.zip\")                  // path to the file you want to validate\n\tchecksumFile := filepath.Join(tmp, \"assets.zip.checksum.txt\") // path to the checksum file\n\n\t// Step 1: Compute the MD5 checksum of the file\n\tstatus <- Status{Text: \"verifying checksum...\"}\n\tcomputedChecksum, err := computeMD5Checksum(filePath)\n\tif err != nil {\n\t\tstatus <- Status{Err: fmt.Errorf(\"Error computing checksum: %v\", err)}\n\t}\n\n\t// Step 2: Read the checksum from the .checksum.txt file\n\tstoredChecksum, err := readChecksumFromFile(checksumFile)\n\tif err != nil {\n\t\tstatus <- Status{Err: err}\n\t}\n\n\t// Step 3: Compare the computed checksum with the stored checksum\n\tif strings.ToLower(computedChecksum) != strings.ToLower(storedChecksum) {\n\t\tstatus <- Status{Err: fmt.Errorf(\"cannot validate update file (checksum mismatch)\")}\n\t}\n\n\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}","sourceCodeStart":404,"sourceCodeEnd":440,"githubUrl":"https://github.com/coreybutler/nvm-windows/blob/5b18223ca19ff50d707f35410dbc6bd440a9f74d/src/upgrade/upgrade.go#L404-L440","documentation":"The MD5 computed over the downloaded assets.zip does not match (case-insensitively) the value in the downloaded .checksum.txt, so nvm-windows refuses to apply the update. This is an integrity guard: the bytes on disk are not the bytes the maintainer signed. Typical causes are a truncated download, a proxy/AV rewriting the body, or an out-of-sync release where the zip and checksum were published from different builds.","triggerScenarios":"Proxy or TLS-inspecting middlebox altering the response body; download cut off mid-transfer (range requests/partial content stitched incorrectly); antivirus appending or modifying content; GitHub release where the zip was re-uploaded after the .checksum.txt; disk corruption in TEMP.","commonSituations":"Corporate SSL-inspection appliances (Netskope, Zscaler, Bluecoat) that re-encode bodies; caching layer (Cache-Control headers are set to no-cache but a broken cache still serves stale mismatched parts); CI images with pre-corrupted caches.","solutions":["Re-run the upgrade to force a fresh, single-connection download — most mismatches are truncated or mixed-origin downloads.","Bypass the proxy/SSL inspection for github.com release URLs, or run from an unrestricted network.","Manually verify: download both assets.zip and assets.zip.checksum.txt, compare with certutil -hashfile <zip> MD5; if they differ upstream, the release itself is broken — report it.","If inspection cannot be disabled, download the nvm-noinstall.zip manually on another machine and install by hand."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Independent verification before trusting the download\ncmd := exec.Command(\"certutil\", \"-hashfile\", zipPath, \"MD5\")\nout, _ := cmd.Output()\nfmt.Println(strings.ToLower(strings.TrimSpace(strings.Split(string(out), \"\\n\")[1])))\n// compare manually against assets.zip.checksum.txt","typeGuard":null,"tryCatchPattern":"Never catch-and-continue a checksum mismatch: it must abort the upgrade unconditionally. Report both computed and stored digests (hex) so the user can see the divergence, then instruct a fresh download from an unfiltered network path.","preventionTips":["Avoid SSL-inspecting proxies for release download hosts.","Re-download fully rather than resuming partial transfers.","Report persistent mismatches upstream — the release itself may be broken."],"tags":["integrity","checksum","network","upgrade"],"backgroundTag":null,"analyzedSha":"5b18223ca19ff50d707f35410dbc6bd440a9f74d","analyzedAt":"2026-08-15T10:06:51.428Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}