twpayne/chezmoi · error
SHA384 mismatch: expected %s, got %s
Error message
SHA384 mismatch: expected %s, got %s
What it means
The SHA384 branch of external checksum verification: if external.Checksum.SHA384 is set and sha384Sum(data) differs, the formatted mismatch error is appended to errs. It is later surfaced wrapped by the external's relative path via errors.Join.
Source
Thrown at internal/chezmoi/sourcestate.go:1738
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)))
}
}
if len(errs) != 0 {
return nil, urlStr, fmt.Errorf("%s: %w", externalRelPath, errors.Join(errs...))
}
if external.Encrypted {
data, err = s.encryption.Decrypt(data)
if err != nil {View on GitHub (pinned to f901167e46)
Solutions
- Recompute with openssl dgst -sha384 <file> (or curl -sL <url> | openssl dgst -sha384) and update checksum.sha384.
- Prefer checksum.sha256, the conventionally supported secure option.
- Ensure the digest is full-length hex (96 hex chars for SHA384).
- Verify the download pipeline (proxy/mirror) isn't altering content.
Example fix
// before checksum.sha384 = "<old digest>" // after checksum.sha384 = "<freshly computed sha384 of the artifact>"
Defensive patterns
Strategy: validation
Validate before calling
openssl dgst -sha384 <file> # or: curl -sL "$URL" | openssl dgst -sha384 # Must yield 96 hex chars matching checksum.sha384.
Try / catch
out, err := exec.Command("chezmoi", "apply").CombinedOutput()
if err != nil && strings.Contains(string(out), "SHA384 mismatch") {
return errors.New("recompute checksum.sha384 from the current artifact")
} Prevention
- Validate digest format (96 hex chars) before committing it.
- Prefer sha256 as the single checksum per external.
- Pin URLs to immutable artifacts.
When it happens
Trigger: External entry declares checksum.sha384; downloaded bytes hash differently than the pinned SHA384 digest.
Common situations: Artifact updated upstream after pinning; checksum generated on a different file or from base64 vs hex confusion; truncated digest in the config.
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
- SHA256 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/42ba8766f461a92e.
Report an issue: GitHub.