twpayne/chezmoi · error
SHA256 mismatch: expected %s, got %s
Error message
SHA256 mismatch: expected %s, got %s
What it means
The SHA256 branch of chezmoi's external checksum verification. If external.Checksum.SHA256 is declared and sha256.Sum256(data) does not match, this error is created and accumulated. SHA256 is the secure, recommended checksum, so no deprecation warning accompanies it.
Source
Thrown at internal/chezmoi/sourcestate.go:1731
errs = append(errs, err)
}
}
if external.Checksum.SHA1 != nil {
s.warnFunc(
"%s: warning: insecure SHA1 checksum will be removed, use a secure hash like SHA256 instead\n",
externalRelPath,
)
if gotSHA1Sum := sha1Sum(data); !bytes.Equal(gotSHA1Sum, external.Checksum.SHA1) {
err := fmt.Errorf("SHA1 mismatch: expected %s, got %s", external.Checksum.SHA1, hex.EncodeToString(gotSHA1Sum))
errs = append(errs, err)
}
}
if external.Checksum.SHA256 != nil {
if gotSHA256Sum := sha256.Sum256(data); !bytes.Equal(gotSHA256Sum[:], external.Checksum.SHA256) {
format := "SHA256 mismatch: expected %s, got %s"
err := fmt.Errorf(format, external.Checksum.SHA256, hex.EncodeToString(gotSHA256Sum[:]))
errs = append(errs, err)
}
}
if external.Checksum.SHA384 != nil {
if gotSHA384Sum := sha384Sum(data); !bytes.Equal(gotSHA384Sum, external.Checksum.SHA384) {
errs = append(errs, fmt.Errorf("SHA384 mismatch: expected %s, got %s",
external.Checksum.SHA384, hex.EncodeToString(gotSHA384Sum)))
}
}
if external.Checksum.SHA512 != nil {
if gotSHA512Sum := sha512Sum(data); !bytes.Equal(gotSHA512Sum, external.Checksum.SHA512) {
errs = append(errs, fmt.Errorf("SHA512 mismatch: expected %s, got %s",
external.Checksum.SHA512, hex.EncodeToString(gotSHA512Sum)))
}
}
View on GitHub (pinned to f901167e46)
Solutions
- Recompute with curl -sL <url> | sha256sum and update checksum.sha256 in .chezmoiexternal.
- Confirm the URL returns the artifact (not an HTML error page) — inspect what you actually downloaded.
- If upstream is trustworthy but volatile, refresh the checksum on each release update.
- Remove the checksum field to skip verification (not recommended).
Example fix
// before checksum.sha256 = "e3b0c44298fc1c14..." // after (recompute for the new release) checksum.sha256 = "<new sha256sum>"
Defensive patterns
Strategy: validation
Validate before calling
# Pre-validate the artifact digest before applying: expected=$(tomlq -r '.starship."checksum.sha256"' .chezmoiexternal.toml) actual=$(curl -sL "$URL" | sha256sum | cut -d' ' -f1) [ "$expected" = "$actual" ] || echo "checksum drift detected"
Try / catch
out, err := exec.Command("chezmoi", "apply").CombinedOutput()
if err != nil && strings.Contains(string(out), "SHA256 mismatch") {
return fmt.Errorf("refresh sha256 in .chezmoiexternal: %s", out)
} Prevention
- Compute sha256 in CI from the exact release asset and commit it with the config change.
- Watch upstream releases (Dependabot/renovate style) and update digest + URL together.
- Use immutable permalinks (tagged releases) so digests stay valid.
- Dry-run apply before real apply to surface drift safely.
When it happens
Trigger: An external entry with checksum.sha256 is fetched and the digest of the downloaded bytes differs from the declared value.
Common situations: Upstream re-released the artifact (checksum pinned in config no longer valid); checksum copied with whitespace/shortened; hashing the wrong file; CDN serving a redirect/error page instead of the artifact.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- MD5 mismatch: expected %s, got %s
- RIPEMD-160 mismatch: expected %s, got %s
- SHA1 mismatch: expected %s, got %s
- SHA384 mismatch: expected %s, got %s
- SHA512 mismatch: expected %s, got %s
AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01).
Data as JSON: /api/errors/48f6d771e267fc7a.
Report an issue: GitHub.