shadowsocks/shadowsocks-windows · error · Exception

Sha256sum mismatch

Error message

Sha256sum mismatch

What it means

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.

Source

Thrown at shadowsocks-csharp/Controller/Service/GeositeUpdater.cs:134

                        logger.Info("Local GeoSite DB is up to date.");
                        UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(false));
                        return;
                    }
                }

                // not latest. download new DB
                var downloadedBytes = await httpClient.GetByteArrayAsync(geositeUrl);

                // verify sha256sum
                if (geositeVerifySha256)
                {
                    byte[] downloadedDBHashBytes = mySHA256.ComputeHash(downloadedBytes);
                    string downloadedDBHash = BitConverter.ToString(downloadedDBHashBytes).Replace("-", String.Empty);
                    logger.Info($"Actual Sha256sum: {downloadedDBHash}");
                    if (geositeSha256sum != downloadedDBHash)
                    {
                        logger.Info("Sha256sum Verification: FAILED. Downloaded GeoSite DB is corrupted. Aborting the update.");
                        throw new Exception("Sha256sum mismatch");
                    }
                    else
                    {
                        logger.Info("Sha256sum Verification: PASSED. Applying to local GeoSite DB.");
                    }
                }

                // write to geosite file
                using (FileStream geositeFileStream = File.Create(DATABASE_PATH))
                    await geositeFileStream.WriteAsync(downloadedBytes, 0, downloadedBytes.Length);

                // update stuff
                geositeDB = downloadedBytes;
                LoadGeositeList();
                bool pacFileChanged = MergeAndWritePACFile(config.geositeDirectGroups, config.geositeProxiedGroups, blacklist);
                UpdateCompleted?.Invoke(null, new GeositeResultEventArgs(pacFileChanged));
            }
            catch (Exception ex)

View on GitHub (pinned to 891d971682)

Solutions

  1. Retry the update once or twice (transient corruption or proxy interception often clears).
  2. Update geositeSha256sum to the hash published alongside the latest DB release so it matches the current upstream artifact.
  3. If running behind a corporate proxy, whitelist the geosite download host so it is not intercepted/rewritten.
  4. Temporarily disable geositeVerifySha256 only if you can confirm the source is trusted and integrity is verified another way.

Example fix

// before
if (geositeSha256sum != downloadedDBHash)
    throw new Exception("Sha256sum mismatch");

// after: log both and retry before failing
logger.Info($"Expected: {geositeSha256sum}, Got: {downloadedDBHash}");
if (geositeSha256sum != downloadedDBHash)
    throw new Exception($"Sha256sum mismatch (expected {geositeSha256sum}, got {downloadedDBHash})");
Defensive patterns

Strategy: retry

Validate before calling

// Pre-validate the expected hash format before comparing
if (string.IsNullOrEmpty(geositeSha256sum) || geositeSha256sum.Length != 64)
{ /* skip verification rather than compare against a bogus hash */ }

Type guard

bool IsValidSha256Hex(string s) =>
    !string.IsNullOrEmpty(s) && s.Length == 64 &&
    s.All(c => (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'));

Try / catch

for (int attempt = 0; attempt < 3; attempt++)
{
    try { await UpdateGeosite(); break; }
    catch (Exception ex) when (ex.Message == "Sha256sum mismatch")
    { if (attempt == 2) throw; await Task.Delay(2000 << attempt); }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.


AI-assisted analysis of shadowsocks/shadowsocks-windows@891d971682 (2026-08-13). Data as JSON: /api/errors/38aec126cdab6a07. Report an issue: GitHub.