twpayne/chezmoi · error

SHA256 mismatch: expected %s, got %s

Error message

SHA256 mismatch: expected %s, got %s

What it means

The SHA256 branch of chezmoi's external checksum verification. If external.Checksum.SHA256 is declared and sha256.Sum256(data) does not match, this error is created and accumulated. SHA256 is the secure, recommended checksum, so no deprecation warning accompanies it.

Source

Thrown at internal/chezmoi/sourcestate.go:1731

			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)))
		}
	}

	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)))
		}
	}

View on GitHub (pinned to f901167e46)

Solutions

  1. Recompute with curl -sL <url> | sha256sum and update checksum.sha256 in .chezmoiexternal.
  2. Confirm the URL returns the artifact (not an HTML error page) — inspect what you actually downloaded.
  3. If upstream is trustworthy but volatile, refresh the checksum on each release update.
  4. Remove the checksum field to skip verification (not recommended).

Example fix

// before
checksum.sha256 = "e3b0c44298fc1c14..."
// after (recompute for the new release)
checksum.sha256 = "<new sha256sum>"
Defensive patterns

Strategy: validation

Validate before calling

# Pre-validate the artifact digest before applying:
expected=$(tomlq -r '.starship."checksum.sha256"' .chezmoiexternal.toml)
actual=$(curl -sL "$URL" | sha256sum | cut -d' ' -f1)
[ "$expected" = "$actual" ] || echo "checksum drift detected"

Try / catch

out, err := exec.Command("chezmoi", "apply").CombinedOutput()
if err != nil && strings.Contains(string(out), "SHA256 mismatch") {
    return fmt.Errorf("refresh sha256 in .chezmoiexternal: %s", out)
}

Prevention

When it happens

Trigger: An external entry with checksum.sha256 is fetched and the digest of the downloaded bytes differs from the declared value.

Common situations: Upstream re-released the artifact (checksum pinned in config no longer valid); checksum copied with whitespace/shortened; hashing the wrong file; CDN serving a redirect/error page instead of the artifact.

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/48f6d771e267fc7a. Report an issue: GitHub.