{"record":{"id":"38aec126cdab6a07","repo":"shadowsocks/shadowsocks-windows","slug":"sha256sum-mismatch","errorCode":null,"errorMessage":"Sha256sum mismatch","messagePattern":"Sha256sum mismatch","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"shadowsocks-csharp/Controller/Service/GeositeUpdater.cs","lineNumber":134,"sourceCode":"                        logger.Info(\"Local GeoSite DB is up to date.\");\n                        UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(false));\n                        return;\n                    }\n                }\n\n                // not latest. download new DB\n                var downloadedBytes = await httpClient.GetByteArrayAsync(geositeUrl);\n\n                // verify sha256sum\n                if (geositeVerifySha256)\n                {\n                    byte[] downloadedDBHashBytes = mySHA256.ComputeHash(downloadedBytes);\n                    string downloadedDBHash = BitConverter.ToString(downloadedDBHashBytes).Replace(\"-\", String.Empty);\n                    logger.Info($\"Actual Sha256sum: {downloadedDBHash}\");\n                    if (geositeSha256sum != downloadedDBHash)\n                    {\n                        logger.Info(\"Sha256sum Verification: FAILED. Downloaded GeoSite DB is corrupted. Aborting the update.\");\n                        throw new Exception(\"Sha256sum mismatch\");\n                    }\n                    else\n                    {\n                        logger.Info(\"Sha256sum Verification: PASSED. Applying to local GeoSite DB.\");\n                    }\n                }\n\n                // write to geosite file\n                using (FileStream geositeFileStream = File.Create(DATABASE_PATH))\n                    await geositeFileStream.WriteAsync(downloadedBytes, 0, downloadedBytes.Length);\n\n                // update stuff\n                geositeDB = downloadedBytes;\n                LoadGeositeList();\n                bool pacFileChanged = MergeAndWritePACFile(config.geositeDirectGroups, config.geositeProxiedGroups, blacklist);\n                UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(pacFileChanged));\n            }\n            catch (Exception ex)","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/shadowsocks/shadowsocks-windows/blob/891d971682eefcaa2e640258d3b352a3ad3b2233/shadowsocks-csharp/Controller/Service/GeositeUpdater.cs#L116-L152","documentation":"Thrown by GeositeUpdater after downloading a GeoSite database when the computed SHA-256 of the downloaded bytes does not equal the expected geositeSha256sum. It is an integrity check: the downloaded DB is considered corrupted or tampered and is not written to disk. The hash is compared in upper-case hex (BitConverter.ToString produces upper-case), so a case mismatch in the expected value would also trigger it.","triggerScenarios":"A network proxy or captive portal returning an HTML/redirect page instead of the DB bytes; a partial download due to a dropped connection that GetByteArrayAsync still completed; the upstream geositeUrl pointing at a file whose hash differs from geositeSha256sum (stale expected hash after a DB republish); a CDN serving a different version than the hash was computed against.","commonSituations":"The geositeSha256sum config was not updated after the upstream published a new DB; a transparent proxy or antivirus intercepting and rewriting the download; mirror/CDN inconsistency where different edges serve different versions; byte-for-byte truncation by an aggressive proxy.","solutions":["Retry the update once or twice (transient corruption or proxy interception often clears).","Update geositeSha256sum to the hash published alongside the latest DB release so it matches the current upstream artifact.","If running behind a corporate proxy, whitelist the geosite download host so it is not intercepted/rewritten.","Temporarily disable geositeVerifySha256 only if you can confirm the source is trusted and integrity is verified another way."],"exampleFix":"// before\nif (geositeSha256sum != downloadedDBHash)\n    throw new Exception(\"Sha256sum mismatch\");\n\n// after: log both and retry before failing\nlogger.Info($\"Expected: {geositeSha256sum}, Got: {downloadedDBHash}\");\nif (geositeSha256sum != downloadedDBHash)\n    throw new Exception($\"Sha256sum mismatch (expected {geositeSha256sum}, got {downloadedDBHash})\");","handlingStrategy":"retry","validationCode":"// Pre-validate the expected hash format before comparing\nif (string.IsNullOrEmpty(geositeSha256sum) || geositeSha256sum.Length != 64)\n{ /* skip verification rather than compare against a bogus hash */ }","typeGuard":"bool IsValidSha256Hex(string s) =>\n    !string.IsNullOrEmpty(s) && s.Length == 64 &&\n    s.All(c => (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'));","tryCatchPattern":"for (int attempt = 0; attempt < 3; attempt++)\n{\n    try { await UpdateGeosite(); break; }\n    catch (Exception ex) when (ex.Message == \"Sha256sum mismatch\")\n    { if (attempt == 2) throw; await Task.Delay(2000 << attempt); }\n}","preventionTips":["Publish the sha256 alongside the DB and update the expected hash in lockstep with the artifact.","Compare hashes case-insensitively to avoid upper/lower hex mismatches.","Retry transient download corruption before failing the whole update."],"tags":["integrity","sha256","download","geosite","verification"],"backgroundTag":null,"analyzedSha":"891d971682eefcaa2e640258d3b352a3ad3b2233","analyzedAt":"2026-08-13T10:12:34.434Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}