twpayne/chezmoi · error

MD5 mismatch: expected %s, got %s

Error message

MD5 mismatch: expected %s, got %s

What it means

chezmoi downloads external file data and verifies it against checksums declared in the source state's external entry. When the MD5 checksum configured in .chezmoiexternal does not match the MD5 of the downloaded bytes, the computed and expected digests are formatted into this error and accumulated. MD5 is deprecated for security, so chezmoi also warns that support will be removed; use SHA256 instead.

Source

Thrown at internal/chezmoi/sourcestate.go:1700

	var errs []error

	if external.Checksum.Size != 0 {
		if external.Checksum.SHA256 == nil && external.Checksum.SHA384 == nil && external.Checksum.SHA512 == nil {
			s.warnFunc("%s: warning: insecure size check without secure hash will be removed\n", externalRelPath)
		}
		if len(data) != external.Checksum.Size {
			err := fmt.Errorf("size mismatch: expected %d, got %d", external.Checksum.Size, len(data))
			errs = append(errs, err)
		}
	}

	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(

View on GitHub (pinned to f901167e46)

Solutions

  1. Recompute the correct checksum: curl the URL and run md5sum, then update checksum.md5 in .chezmoiexternal.
  2. Prefer a secure hash: compute sha256sum and declare checksum.sha256 instead (MD5 support is being removed).
  3. If upstream is genuinely volatile, drop the checksum field entirely (losing integrity verification).
  4. Check the download path (proxy/mirror) is serving the exact bytes you hashed.

Example fix

// before (.chezmoiexternal.toml)
[.tmux.conf]
  type = "file"
  url = "https://example.com/tmux.conf"
  checksum.md5 = "abcd1234"
// after
  # md5sum tmux.conf  -> e3b0c44298fc1c149afbf4c8996fb924
  checksum.sha256 = "<sha256 of file>"
Defensive patterns

Strategy: validation

Validate before calling

# Verify the checksum before chezmoi does:
curl -sL "https://example.com/artifact" | md5sum
# Compare with checksum.md5 in .chezmoiexternal; prefer:
curl -sL "https://example.com/artifact" | sha256sum

Try / catch

// Run `chezmoi apply --dry-run` (or `chezmoi diff`) and treat any output containing
// 'MD5 mismatch' as a hard stop; fix .chezmoiexternal before applying.
if err := run("chezmoi", "apply", "--dry-run"); strings.Contains(err.Error(), "mismatch") {
    return fmt.Errorf("external checksum drift: %w", err)
}

Prevention

When it happens

Trigger: An external entry in .chezmoiexternal with a checksum.md5 field is fetched; md5Sum(data) differs from external.Checksum.MD5. Happens when the upstream file changed since the checksum was recorded, or the checksum was copy-pasted/truncated incorrectly.

Common situations: Pinning a GitHub release tarball by MD5 that upstream re-released; hand-computing the checksum on a different file; proxy or mirror serving altered content; declaring an MD5 checksum against a file that is actually SHA256-encoded hex.

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/4b7b95d544216d3f. Report an issue: GitHub.