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

  1. Recompute with openssl dgst -sha384 <file> (or curl -sL <url> | openssl dgst -sha384) and update checksum.sha384.
  2. Prefer checksum.sha256, the conventionally supported secure option.
  3. Ensure the digest is full-length hex (96 hex chars for SHA384).
  4. 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

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


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