{"record":{"id":"344113c0769d3f40","repo":"siyuan-note/siyuan","slug":"checksum-manifest-digest-mismatch","errorCode":null,"errorMessage":"checksum manifest digest mismatch","messagePattern":"checksum manifest digest mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/updater_release.go","lineNumber":404,"sourceCode":"\t}\n\tif nil == response || nil == response.Response {\n\t\treturn \"\", errors.New(\"checksum manifest response is empty\")\n\t}\n\tdefer response.Body.Close()\n\tif 200 != response.StatusCode {\n\t\treturn \"\", fmt.Errorf(\"get checksum manifest failed: %d\", response.StatusCode)\n\t}\n\tdata, err := io.ReadAll(io.LimitReader(response.Body, maxChecksumManifestSize+1))\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\tif maxChecksumManifestSize < int64(len(data)) {\n\t\treturn \"\", errors.New(\"checksum manifest is too large\")\n\t}\n\tif \"\" != manifestDigest {\n\t\tactualDigest := fmt.Sprintf(\"%x\", sha256.Sum256(data))\n\t\tif manifestDigest != actualDigest {\n\t\t\treturn \"\", errors.New(\"checksum manifest digest mismatch\")\n\t\t}\n\t}\n\tmanifest := string(data)\n\tif \"\" != manifestCacheKey {\n\t\tgithubManifestCache.Store(manifestCacheKey, manifest)\n\t}\n\tchecksum := parseChecksumManifest(manifest, pkgName)\n\tif \"\" == checksum {\n\t\treturn \"\", errors.New(\"package checksum is unavailable\")\n\t}\n\treturn checksum, nil\n}\n\nfunc parseChecksumManifest(manifest, pkgName string) string {\n\tfor _, line := range strings.Split(manifest, \"\\n\") {\n\t\tfields := strings.Fields(line)\n\t\tif 2 > len(fields) {\n\t\t\tcontinue","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/updater_release.go#L386-L422","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Retry the update check — a transiently corrupted or interrupted download is the most common cause; the next fetch re-downloads and re-verifies","Disable or bypass HTTP proxies/interceptors for GitHub (unset HTTP_PROXY/HTTPS_PROXY or allowlist github.com) so the manifest is fetched unmodified","Check SiYuan version: if the release was re-published upstream, wait for a new release rather than accepting the stale manifest","Verify network integrity (DNS hijack / MITM); compare the manifest downloaded manually (sha256sum) against the digest in the release metadata","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"],"exampleFix":"// no code fix on the caller side; network-side fix\n// before (proxied)\nHTTPS_PROXY=http://corp-proxy:8080 ./siyuan\n// after (bypass proxy for GitHub)\nNO_PROXY=github.com,objects.githubusercontent.com ./siyuan","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Go caller of the update check\nif checksum, err := getGitHubUpdateRelease(ctx); err != nil {\n    if strings.Contains(err.Error(), \"digest mismatch\") {\n        log.Warn(\"manifest digest mismatch; likely proxy/CDN tampering, retrying without proxy\")\n        // retry after disabling proxy / after backoff\n    }\n}","preventionTips":["Allowlist github.com in proxy/SSL-interception settings so release assets pass unmodified","Retry update checks with backoff before treating a mismatch as fatal","Verify manual sha256 of the manifest when mismatches recur to distinguish transient corruption from tampering"],"tags":["network","integrity","checksum","update"],"backgroundTag":"checksum-mismatch","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}