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

  1. Recompute: curl -sL <url> | sha1sum and update checksum.sha1.
  2. Switch to checksum.sha256 for both security and future compatibility.
  3. Ensure you hash the same byte stream chezmoi downloads (before decryption/decompression).
  4. 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

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


AI-assisted analysis of twpayne/chezmoi@f901167e46 (2026-09-01). Data as JSON: /api/errors/c560350c43297245. Report an issue: GitHub.