twpayne/chezmoi · error

RIPEMD-160 mismatch: expected %s, got %s

Error message

RIPEMD-160 mismatch: expected %s, got %s

What it means

Same verification flow as other checksums: if external.Checksum.RIPEMD160 is set in the external entry and ripemd160Sum(data) does not match the downloaded data, chezmoi emits this mismatch error. RIPEMD-160 is flagged as insecure and slated for removal, so a SHA256 checksum is recommended.

Source

Thrown at internal/chezmoi/sourcestate.go:1712

	if external.Checksum.MD5 != nil {
		s.warnFunc(
			"%s: warning: insecure MD5 checksum will be removed, use a secure hash like SHA256 instead\n",
			externalRelPath,
		)
		if gotMD5Sum := md5Sum(data); !bytes.Equal(gotMD5Sum, external.Checksum.MD5) {
			err := fmt.Errorf("MD5 mismatch: expected %s, got %s", external.Checksum.MD5, hex.EncodeToString(gotMD5Sum))
			errs = append(errs, err)
		}
	}

	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"

View on GitHub (pinned to f901167e46)

Solutions

  1. Recompute with a RIPEMD-160 tool (e.g. openssl rmd160 file) and update checksum.ripemd160.
  2. Migrate the checksum to checksum.sha256, since RIPEMD-160 support will be removed.
  3. Verify the URL still points at the exact release/artifact you pinned.
  4. Remove the checksum if you accept unverified downloads.

Example fix

// before
checksum.ripemd160 = "9c1185a5c5e9fc54612808977ee8f548"
// after
checksum.sha256 = "<sha256 of the downloaded file>"
Defensive patterns

Strategy: validation

Validate before calling

openssl rmd160 <downloaded-file>
# Compare with checksum.ripemd160 before applying; prefer sha256 instead.

Try / catch

// Detect RIPEMD-160 mismatch in a wrapper and fail fast:
out, err := exec.Command("chezmoi", "apply").CombinedOutput()
if err != nil && strings.Contains(string(out), "RIPEMD-160 mismatch") {
    return errors.New("refresh checksum.ripemd160 in .chezmoiexternal")
}

Prevention

When it happens

Trigger: Fetching an external whose checksum.ripemd160 field was declared; the computed RIPEMD-160 digest of the downloaded bytes differs from the declared value.

Common situations: Legacy external configs copied from old dotfile repos; upstream file updated after the checksum was pinned; typo'd or hex/base64 confusion when transcribing the digest.

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/480947ddf49023f4. Report an issue: GitHub.