henrygd/beszel · error
hash mismatch: got %s want %s
Error message
hash mismatch: got %s want %s
What it means
downloadFile in fetchsmartctl verifies the downloaded binary against an expected SHA hash (normalized to lowercase, whitespace-stripped). After hashing the downloaded temp file, it compares the computed hex digest to the expected value and fails the download if they differ, deleting the temp file. This protects against corrupted or tampered binaries.
Source
Thrown at agent/tools/fetchsmartctl/main.go:109
if hasher != nil {
mw = io.MultiWriter(f, hasher)
}
if _, err := io.Copy(mw, resp.Body); err != nil {
f.Close()
os.Remove(tmp)
return fmt.Errorf("write tmp: %w", err)
}
if err := f.Close(); err != nil {
os.Remove(tmp)
return fmt.Errorf("close tmp: %w", err)
}
if hasher != nil && shaHex != "" {
cleanSha := strings.ToLower(strings.ReplaceAll(strings.TrimSpace(shaHex), " ", ""))
got := strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))
if got != cleanSha {
os.Remove(tmp)
return fmt.Errorf("hash mismatch: got %s want %s", got, cleanSha)
}
}
// Make executable and move into place
if err := os.Chmod(tmp, 0o755); err != nil {
os.Remove(tmp)
return fmt.Errorf("chmod: %w", err)
}
if err := os.Rename(tmp, dest); err != nil {
os.Remove(tmp)
return fmt.Errorf("rename: %w", err)
}
fmt.Println("smartctl.exe downloaded to", dest)
return nil
}
func fatalf(format string, a ...any) {View on GitHub (pinned to b38fb7dafa)
Solutions
- Check upstream release notes for the new smartctl.exe version and update the pinned hash constant to the official SHA-256 for that exact file.
- Re-download manually and compute `sha256sum smartctl.exe` to confirm what the remote is actually serving; if it differs from upstream, suspect a proxy/mirror serving modified content.
- Verify the pinned hash is the SHA-256 hex digest (64 hex chars) of the binary itself, not of an archive or signature file.
- If the download was truncated, retry or fix the network, then re-run fetchsmartctl.
Example fix
// before shaHex = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" // stale pin // after // $ sha256sum smartctl.exe (hash of the release actually being fetched) shaHex = "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
Defensive patterns
Strategy: validation
Validate before calling
// verify the pinned hash matches the exact artifact you serve before calling downloadFile
sum := sha256.Sum256(expectedArtifactBytes)
if !strings.EqualFold(hex.EncodeToString(sum[:]), expectedShaHex) {
return errors.New("pinned hash does not match known artifact; update it")
} Try / catch
if err := downloadFile(url, dest, sha256Hex); err != nil {
if strings.HasPrefix(err.Error(), "hash mismatch") {
log.Printf("integrity check failed: %v", err) // refresh hash or abort
} else {
return err
}
} Prevention
- Pin hash and release version together; update both in the same commit.
- Hash the exact artifact downloaded (not the zip/signature).
- Never bypass verification; log got/want on mismatch.
- Watch for proxies/CDNs altering binary content.
When it happens
Trigger: The expected sha256 string (shaHex) does not match the actual hash of the bytes fetched from the remote URL: wrong/pinned hash for a different smartctl.exe release, truncated or proxied/modified download, or a hash string referring to a different file after cleanup.
Common situations: Upstream smartmontools updated the binary but the script still pins the old hash; corporate proxy or CDN serving different content; copy-paste error in the embedded hash (wrong algorithm, e.g. SHA-1 instead of SHA-256, or hash of a zip instead of the exe).
Related errors
AI-assisted analysis of henrygd/beszel@b38fb7dafa (2026-08-31).
Data as JSON: /api/errors/0c8567b07d36cfda.
Report an issue: GitHub.