coreybutler/nvm-windows · critical

cannot validate update file (checksum mismatch)

Error message

cannot validate update file (checksum mismatch)

What it means

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.

Source

Thrown at src/upgrade/upgrade.go:422

	filePath := filepath.Join(tmp, "assets.zip")                  // path to the file you want to validate
	checksumFile := filepath.Join(tmp, "assets.zip.checksum.txt") // path to the checksum file

	// Step 1: Compute the MD5 checksum of the file
	status <- Status{Text: "verifying checksum..."}
	computedChecksum, err := computeMD5Checksum(filePath)
	if err != nil {
		status <- Status{Err: fmt.Errorf("Error computing checksum: %v", err)}
	}

	// Step 2: Read the checksum from the .checksum.txt file
	storedChecksum, err := readChecksumFromFile(checksumFile)
	if err != nil {
		status <- Status{Err: err}
	}

	// Step 3: Compare the computed checksum with the stored checksum
	if strings.ToLower(computedChecksum) != strings.ToLower(storedChecksum) {
		status <- Status{Err: fmt.Errorf("cannot validate update file (checksum mismatch)")}
	}

	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
			}

View on GitHub (pinned to 5b18223ca1)

Solutions

  1. Re-run the upgrade to force a fresh, single-connection download — most mismatches are truncated or mixed-origin downloads.
  2. Bypass the proxy/SSL inspection for github.com release URLs, or run from an unrestricted network.
  3. 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.
  4. If inspection cannot be disabled, download the nvm-noinstall.zip manually on another machine and install by hand.
Defensive patterns

Strategy: validation

Validate before calling

// Independent verification before trusting the download
cmd := exec.Command("certutil", "-hashfile", zipPath, "MD5")
out, _ := cmd.Output()
fmt.Println(strings.ToLower(strings.TrimSpace(strings.Split(string(out), "\n")[1])))
// compare manually against assets.zip.checksum.txt

Try / catch

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.

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of coreybutler/nvm-windows@5b18223ca1 (2026-08-15). Data as JSON: /api/errors/4e8e181d234fcc18. Report an issue: GitHub.