elastic/elasticsearch · error · RuntimeException

Unexpected md5 response from [{}]

Error message

Unexpected md5 response from [{}]

What it means

Thrown by IpinfoDownload.checksum() after fetching the checksums JSON from Ipinfo. The JSON's checksums.md5 value must match MD5_CHECKSUM_PATTERN = (\w{32}); a missing md5 field, a null, or any non-32-hex value triggers this. It is a RuntimeException propagating out of checksum() and aborting the download.

Source

Thrown at modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/EnterpriseGeoIpDownloader.java:595

            return Strings.format(endpointPattern, internalName, suffix);
        }

        @Override
        public Checksum checksum() throws IOException {
            final String checksumJsonUrl = this.url("mmdb/checksums"); // a minor abuse of the idea of a 'suffix', :shrug:
            byte[] data = httpClient.getBytes(auth.get(), checksumJsonUrl); // this throws if the auth is bad
            Map<String, Object> checksums;
            try (XContentParser parser = XContentType.JSON.xContent().createParser(XContentParserConfiguration.EMPTY, data)) {
                checksums = parser.map();
            }
            @SuppressWarnings("unchecked")
            String md5 = ((Map<String, String>) checksums.get("checksums")).get("md5");
            logger.trace("checksum was [{}]", md5);

            var matcher = MD5_CHECKSUM_PATTERN.matcher(md5);
            boolean match = matcher.matches();
            if (match == false) {
                throw new RuntimeException("Unexpected md5 response from [" + checksumJsonUrl + "]");
            }
            return Checksum.md5(md5);
        }

        @Override
        public CheckedSupplier<InputStream, IOException> download() {
            final String mmdbUrl = this.url("mmdb");
            return () -> httpClient.get(auth.get(), mmdbUrl);
        }

        @Override
        public void close() throws IOException {
            if (auth != null) auth.close();
        }
    }

    interface ProviderDownload extends Closeable {
        // note: buildCredentials and url are inherently just implementation details of checksum() and download(),

View on GitHub (pinned to db6a809a66)

Solutions

  1. Manually fetch the checksumJsonUrl with the configured token to inspect the response body and confirm an md5 field is present.
  2. Validate/regenerate the Ipinfo token in secure settings.
  3. Confirm the Ipinfo endpoint base URL is correct and not redirected to a generic host.
  4. If Ipinfo changed the schema, update MD5_CHECKSUM_PATTERN or the JSON field extraction (code change).
Defensive patterns

Strategy: try-catch

Try / catch

try {
    Checksum cs = ipinfoDownload.checksum();
} catch (RuntimeException e) {
    // message starts with "Unexpected md5 response from"
    // fetch the checksumJsonUrl manually, verify md5 field present, fix token/endpoint, retry next schedule
    logger.error("ipinfo md5 body unparseable for [{}]", checksumJsonUrl, e);
}

Prevention

When it happens

Trigger: IpinfoDownload.checksum() -> httpClient.getBytes(auth, checksumJsonUrl) -> parse JSON -> extract checksums.md5 -> matcher.matches() == false. Common when the token is wrong and Ipinfo returns a 200 JSON error with no md5, or when Ipinfo changes its checksum schema.

Common situations: Invalid/expired Ipinfo token returning a JSON error body; Ipinfo schema change; corporate proxy returning an HTML error that fails JSON parsing earlier or yields a non-md5 string; NPE-style issue if md5 is null (matcher would NPE before this line in some cases).

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/3a93215f2fb8093f. Report an issue: GitHub.