twpayne/chezmoi · error
SHA1 mismatch: expected %s, got %s
Error message
SHA1 mismatch: expected %s, got %s
What it means
chezmoi verifies the downloaded external data against external.Checksum.SHA1. A mismatch between the declared SHA1 and sha1Sum(data) produces this error and is appended to the error list. SHA1 is considered insecure and its support will be removed; SHA256 is the recommended replacement.
Source
Thrown at internal/chezmoi/sourcestate.go:1723
if external.Checksum.RIPEMD160 != nil {
s.warnFunc(
"%s: warning: insecure RIPEMD-160 checksum will be removed, use a secure hash like SHA256 instead\n",
externalRelPath,
)
if gotRIPEMD160Sum := ripemd160Sum(data); !bytes.Equal(gotRIPEMD160Sum, external.Checksum.RIPEMD160) {
format := "RIPEMD-160 mismatch: expected %s, got %s"
err := fmt.Errorf(format, external.Checksum.RIPEMD160, hex.EncodeToString(gotRIPEMD160Sum))
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)))
}
}View on GitHub (pinned to f901167e46)
Solutions
- Recompute: curl -sL <url> | sha1sum and update checksum.sha1.
- Switch to checksum.sha256 for both security and future compatibility.
- Ensure you hash the same byte stream chezmoi downloads (before decryption/decompression).
- Remove the checksum if unverified download is acceptable.
Example fix
// before checksum.sha1 = "2aae6c35c94fcfb415dbe95f408b9ce9" // after checksum.sha256 = "<sha256sum of the artifact>"
Defensive patterns
Strategy: validation
Validate before calling
curl -sL "$URL" | sha1sum # Compare with checksum.sha1; prefer: curl -sL "$URL" | sha256sum
Try / catch
out, err := exec.Command("chezmoi", "apply").CombinedOutput()
if err != nil && strings.Contains(string(out), "SHA1 mismatch") {
return errors.New("update checksum.sha1 (or switch to sha256) in .chezmoiexternal")
} Prevention
- Hash the same byte stream chezmoi sees: pre-decrypt, pre-decompress.
- Standardize on sha256 for all externals.
- Re-pin checksums whenever you bump the artifact version.
When it happens
Trigger: An external entry declares checksum.sha1; the downloaded bytes hash to a different digest than the declared one.
Common situations: Old configs pinned with SHA1 (common in legacy dotfiles repos); upstream replaced the artifact; hashing the decompressed file while chezmoi verifies the compressed download (or vice versa).
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
- SHA256 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/c560350c43297245.
Report an issue: GitHub.