{"record":{"id":"9ef112291d13f60c","repo":"elastic/elasticsearch","slug":"md5-checksum-mismatch-expected-actual","errorCode":null,"errorMessage":"md5 checksum mismatch, expected [{}], actual [{}]","messagePattern":"md5 checksum mismatch, expected \\[(.+?)\\], actual \\[(.+?)\\]","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/GeoIpDownloader.java","lineNumber":274,"sourceCode":"            md.update(buf);\n            IndexRequest indexRequest = new IndexRequest(DATABASES_INDEX).id(name + \"_\" + chunk + \"_\" + timestamp)\n                .create(true)\n                .source(XContentType.SMILE, \"name\", name, \"chunk\", chunk, \"data\", buf);\n            client.index(indexRequest).actionGet();\n            chunk++;\n        }\n\n        // May take some time before automatic flush kicks in:\n        // (otherwise the translog will contain large documents for some time without good reason)\n        FlushRequest flushRequest = new FlushRequest(DATABASES_INDEX);\n        client.admin().indices().flush(flushRequest).actionGet();\n        // Ensure that the chunk documents are visible:\n        RefreshRequest refreshRequest = new RefreshRequest(DATABASES_INDEX);\n        client.admin().indices().refresh(refreshRequest).actionGet();\n\n        String actualMd5 = MessageDigests.toHexString(md.digest());\n        if (Objects.equals(expectedMd5, actualMd5) == false) {\n            throw new IOException(\"md5 checksum mismatch, expected [\" + expectedMd5 + \"], actual [\" + actualMd5 + \"]\");\n        }\n        return chunk;\n    }\n\n    // visible for testing\n    static byte[] getChunk(InputStream is) throws IOException {\n        byte[] buf = new byte[MAX_CHUNK_SIZE];\n        int chunkSize = 0;\n        while (chunkSize < MAX_CHUNK_SIZE) {\n            int read = is.read(buf, chunkSize, MAX_CHUNK_SIZE - chunkSize);\n            if (read == -1) {\n                break;\n            }\n            chunkSize += read;\n        }\n        if (chunkSize < MAX_CHUNK_SIZE) {\n            buf = Arrays.copyOf(buf, chunkSize);\n        }","sourceCodeStart":256,"sourceCodeEnd":292,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/GeoIpDownloader.java#L256-L292","documentation":"Thrown by GeoIpDownloader.indexChunks (the non-enterprise legacy path) after indexing all chunks of a database and flushing/refreshing the .geoip database index. The md5 of the streamed bytes is compared against the expected md5 from the provider; a mismatch means the downloaded bytes do not match what the provider advertised. IOException, so it is treated as a retryable download failure.","triggerScenarios":"GeoIpDownloader download flow -> indexChunks computes MessageDigests.toHexString(md.digest()) and compares to expectedMd5; mismatch throws IOException at the Objects.equals check.","commonSituations":"Truncated or corrupted download; proxy returning a partial/error body; unstable connection to the public geoip endpoint; mismatch between expected md5 (stale) and the freshly served file.","solutions":["Allow the next scheduled download to retry; transient mismatches usually clear.","Verify the network path to the public geoip database host is clean (no intercepting proxy).","Compare expected vs actual md5 in the logs: a wildly different actual suggests an error body; a near miss suggests truncation.","Re-trigger the download manually or restart the ingest node if the stale-expected-md5 condition persists."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    downloader.indexChunks(name, is, chunk, expectedMd5, ts);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"md5 checksum mismatch\")) {\n        // discard partial chunks, re-fetch, retry once; then let the scheduler handle it\n        throw e;\n    }\n    throw e;\n}","preventionTips":["Keep the download path clean of intercepting proxies.","Treat md5 mismatch as transient and rely on scheduled retries.","Compare expected vs actual md5 in logs to diagnose proxy/truncation.","Ensure credentials are valid to avoid hashing an error body."],"tags":["geoip","checksum","network","download","data-integrity"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}