router-for-me/CLIProxyAPI · critical

checksum mismatch for %s

Error message

checksum mismatch for %s

What it means

VerifyChecksum compares the SHA-256 hex digest of the supplied data bytes against the entry for `name` in the plugin store's checksums map. It throws 'checksum mismatch for %s' when the computed digest does not equal the (lower-cased, trimmed) expected value. This is an integrity guard: it fires after download when the file content has been corrupted, truncated, or replaced relative to what the store manifest declares.

Source

Thrown at internal/pluginstore/checksum.go:42

		}
		if _, errDecode := hex.DecodeString(hash); errDecode != nil {
			return nil, fmt.Errorf("line %d: invalid sha256: %w", lineNumber+1, errDecode)
		}
		name := strings.TrimPrefix(strings.TrimSpace(fields[1]), "*")
		out[name] = hash
	}
	return out, nil
}

func VerifyChecksum(name string, data []byte, checksums map[string]string) error {
	expected := strings.ToLower(strings.TrimSpace(checksums[name]))
	if expected == "" {
		return fmt.Errorf("checksum for %s not found", name)
	}
	actualBytes := sha256.Sum256(data)
	actual := hex.EncodeToString(actualBytes[:])
	if actual != expected {
		return fmt.Errorf("checksum mismatch for %s", name)
	}
	return nil
}

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Re-download the data from the plugin store and retry VerifyChecksum — transient corruption is the most common cause.
  2. Confirm the checksums map comes from the same index version as the downloaded file (refresh the store index).
  3. If the checksum map is maintained locally, verify the digest independently (sha256sum on the file) and update the stale entry if the upstream legitimately changed.
  4. Inspect the downloaded bytes (e.g. check for an HTML error page or zero length) to identify a proxy/network interceptor.

Example fix

// before
data, _ := client.DownloadArtifact(ctx, artifact)
if err := pluginstore.VerifyChecksum(artifact.Name, data, oldChecksums); err != nil {
    return err // fails after index refresh
}

// after
index, err := client.FetchIndex(ctx) // refresh checksum map first
if err != nil { return err }
data, err := client.DownloadArtifact(ctx, artifact)
if err != nil { return err }
if err := pluginstore.VerifyChecksum(artifact.Name, data, index.Checksums); err != nil {
    return err
}
Defensive patterns

Strategy: validation

Validate before calling

if expected := strings.TrimSpace(checksums[name]); expected == "" {
    return fmt.Errorf("no checksum entry for %q — refresh the plugin index", name)
}
// pre-compute before verifying so a mismatch is diagnosable
sum := sha256.Sum256(data)
log.Debugf("%s expected=%s actual=%s", name, strings.ToLower(expected), hex.EncodeToString(sum[:]))

Try / catch

if err := pluginstore.VerifyChecksum(name, data, checksums); err != nil {
    if strings.Contains(err.Error(), "checksum mismatch") {
        // do NOT install; re-download once, then surface as tamper/corruption
    }
    return err
}

Prevention

When it happens

Trigger: Calling VerifyChecksum(name, data, checksums) where sha256(data) != strings.ToLower(checksums[name]); typically invoked right after fetching a file (e.g. an index or artifact) listed in the plugin store checksum map. Partial downloads, proxy-injected error pages, or a stale checksum map paired with a newer file all trigger it.

Common situations: A CDN or corporate proxy returns an HTML error page instead of the binary; the plugin index was regenerated but the caller cached the old checksums map; a truncated download caused by a dropped connection; uppercase-vs-lowercase hex is already handled, so real content divergence is the usual cause.

Related errors


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