{"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":"validation","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/251596fc0de2f9528c00c224252fd073a99973f4/kernel/model/updater_release.go#L386-L422","documentation":"Returned by getGitHubManifestChecksum when the GitHub asset's declared Digest (a sha256 of the manifest file, exposed via the asset metadata) is present but does not equal the SHA-256 computed over the downloaded bytes. This is an integrity check on the checksum file itself — a self-validating guard that the manifest wasn't tampered with in transit or by a mirror.","triggerScenarios":"A proxy or CDN altered the manifest bytes. The asset's declared Digest in the GitHub API response is stale relative to the actual asset content. MITM serving a different manifest. GitHub's asset digest field is inconsistent due to a re-upload.","commonSituations":"Corporate proxy that re-encodes or injects into downloads. A mirror caching a stale manifest after a release was re-published. A CDN serving a partial manifest whose digest no longer matches.","solutions":["Retry from a different network or after bypassing the proxy to rule out in-transit modification.","Switch to the stable channel (independent checksum source).","Download the manifest directly from GitHub in a browser and compare its SHA-256 to the asset's declared digest to localize the discrepancy."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// On digest mismatch, do NOT trust the bytes; switch source.\nchecksum, err := getGitHubManifestChecksum(ctx, release, pkgName)\nif err != nil && strings.Contains(err.Error(), \"digest mismatch\") {\n    logging.LogErrorf(\"manifest tampered in transit; falling back: %s\", err)\n    checksum = getStablePackageChecksum(rhyResult, pkgName)\n}","preventionTips":["Never ignore a digest mismatch — it signals in-transit tampering or a stale mirror.","Retry from a different network to localize proxy/captive-portal interference.","Fall back to the stable cloud JSON checksums rather than disabling the digest check."],"tags":["update","checksum","manifest","integrity","security","mitm"],"backgroundTag":null,"analyzedSha":"251596fc0de2f9528c00c224252fd073a99973f4","analyzedAt":"2026-08-12T21:18:37.123Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}