siyuan-note/siyuan · error

checksum manifest digest mismatch

Error message

checksum manifest digest mismatch

What it means

During a SiYuan auto-update check, getGitHubManifestChecksum downloads the SHA256 checksum manifest for a GitHub release and, when a trusted manifest digest (hash of the manifest itself) is supplied, compares it against the SHA256 of the downloaded bytes. A mismatch means the manifest bytes were altered in transit or served by something other than the expected release — a supply-chain integrity guard. The update is aborted rather than verifying package checksums against a possibly forged manifest.

Solutions

  1. Retry the update check — a transiently corrupted or interrupted download is the most common cause; the next fetch re-downloads and re-verifies
  2. Disable or bypass HTTP proxies/interceptors for GitHub (unset HTTP_PROXY/HTTPS_PROXY or allowlist github.com) so the manifest is fetched unmodified
  3. Check SiYuan version: if the release was re-published upstream, wait for a new release rather than accepting the stale manifest
  4. Verify network integrity (DNS hijack / MITM); compare the manifest downloaded manually (sha256sum) against the digest in the release metadata
  5. If it persists on every attempt with a stock build, report it on siyuan-note/siyuan — the published metadata and manifest are out of sync

Example fix

// no code fix on the caller side; network-side fix
// before (proxied)
HTTPS_PROXY=http://corp-proxy:8080 ./siyuan
// after (bypass proxy for GitHub)
NO_PROXY=github.com,objects.githubusercontent.com ./siyuan
Defensive patterns

Strategy: retry

Try / catch

// Go caller of the update check
if checksum, err := getGitHubUpdateRelease(ctx); err != nil {
    if strings.Contains(err.Error(), "digest mismatch") {
        log.Warn("manifest digest mismatch; likely proxy/CDN tampering, retrying without proxy")
        // retry after disabling proxy / after backoff
    }
}

Prevention

When it happens

Trigger: Calling getGitHubUpdateRelease (update check against GitHub releases) where the release metadata supplies a manifestDigest but the bytes fetched from manifestAsset.BrowserDownloadURL hash to a different SHA256 — e.g. a proxy/mirror returning rewritten content, a cached/stale CDN response, or a re-uploaded manifest without updated metadata.

Common situations: Corporate or national proxies (GitHub accessed via mirror) serving modified manifests; GitHub release assets replaced after metadata was generated; transparent TLS interception; flaky download truncated/extended then re-hashed differently; running an unofficial build whose expected digest drifted from the published manifest.

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 siyuan-note/siyuan@9f775e8a12 (2026-09-19). Data as JSON: /api/errors/344113c0769d3f40. Report an issue: GitHub.

Appendix: source

Thrown at kernel/model/updater_release.go:404

	}
	if nil == response || nil == response.Response {
		return "", errors.New("checksum manifest response is empty")
	}
	defer response.Body.Close()
	if 200 != response.StatusCode {
		return "", fmt.Errorf("get checksum manifest failed: %d", response.StatusCode)
	}
	data, err := io.ReadAll(io.LimitReader(response.Body, maxChecksumManifestSize+1))
	if err != nil {
		return "", err
	}
	if maxChecksumManifestSize < int64(len(data)) {
		return "", errors.New("checksum manifest is too large")
	}
	if "" != manifestDigest {
		actualDigest := fmt.Sprintf("%x", sha256.Sum256(data))
		if manifestDigest != actualDigest {
			return "", errors.New("checksum manifest digest mismatch")
		}
	}
	manifest := string(data)
	if "" != manifestCacheKey {
		githubManifestCache.Store(manifestCacheKey, manifest)
	}
	checksum := parseChecksumManifest(manifest, pkgName)
	if "" == checksum {
		return "", errors.New("package checksum is unavailable")
	}
	return checksum, nil
}

func parseChecksumManifest(manifest, pkgName string) string {
	for _, line := range strings.Split(manifest, "\n") {
		fields := strings.Fields(line)
		if 2 > len(fields) {
			continue

View on GitHub (pinned to 9f775e8a12)