elastic/elasticsearch · error · IllegalStateException

cloudId {} did not decode to a cluster identifier correctly

Error message

cloudId {} did not decode to a cluster identifier correctly

What it means

After stripping the optional human-readable prefix and Base64-decoding, the cloudId must split on '$' into exactly three parts: domain[:port], elasticsearch id, kibana id. Any other count means the cloudId is structurally invalid and the cluster endpoint cannot be derived.

Source

Thrown at client/rest/src/main/java/org/elasticsearch/client/RestClient.java:173

     * @param cloudId a valid elastic cloud cloudId that will route to a cluster. The cloudId is located in
     *                the user console https://cloud.elastic.co and will resemble a string like the following
     *                optionalHumanReadableName:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRlbGFzdGljc2VhcmNoJGtpYmFuYQ==
     */
    public static RestClientBuilder builder(String cloudId) {
        // there is an optional first portion of the cloudId that is a human readable string, but it is not used.
        if (cloudId.contains(":")) {
            if (cloudId.indexOf(':') == cloudId.length() - 1) {
                throw new IllegalStateException("cloudId " + cloudId + " must begin with a human readable identifier followed by a colon");
            }
            cloudId = cloudId.substring(cloudId.indexOf(':') + 1);
        }

        String decoded = new String(Base64.getDecoder().decode(cloudId), UTF_8);
        // once decoded the parts are separated by a $ character.
        // they are respectively domain name and optional port, elasticsearch id, kibana id
        String[] decodedParts = decoded.split("\\$");
        if (decodedParts.length != 3) {
            throw new IllegalStateException("cloudId " + cloudId + " did not decode to a cluster identifier correctly");
        }

        // domain name and optional port
        String[] domainAndMaybePort = decodedParts[0].split(":", 2);
        String domain = domainAndMaybePort[0];
        int port;

        if (domainAndMaybePort.length == 2) {
            try {
                port = Integer.parseInt(domainAndMaybePort[1]);
            } catch (NumberFormatException nfe) {
                throw new IllegalStateException("cloudId " + cloudId + " does not contain a valid port number");
            }
        } else {
            port = 443;
        }

        String url = decodedParts[1] + "." + domain;

View on GitHub (pinned to db6a809a66)

Solutions

  1. Re-copy the cloudId verbatim from the Elastic Cloud deployment's 'Cloud ID' field.
  2. Verify the Base64 decodes to a string with exactly two '$' separators.
  3. If migrating deployments, generate a fresh cloudId for the new deployment.

Example fix

// before
RestClient.builder("not-valid-base64-payload");
// after
RestClient.builder("MyDeploy:dXMtZWFzdC0xLmF3cy5mb3VuZC5pbyRlbGFzdGljc2VhcmNoJGtpYmFuYQ==");
Defensive patterns

Strategy: validation

Validate before calling

static boolean cloudIdDecodesToThreeParts(String cloudId) {
    String payload = cloudId.contains(":") ? cloudId.substring(cloudId.indexOf(':') + 1) : cloudId;
    try {
        String decoded = new String(Base64.getDecoder().decode(payload));
        return decoded.split("\\$").length == 3;
    } catch (IllegalArgumentException e) { return false; }
}

Try / catch

try { RestClient.builder(cloudId); } catch (IllegalStateException e) { /* re-copy cloudId; it is malformed */ }

Prevention

When it happens

Trigger: Passing a cloudId whose decoded form has 2 or 4+ '$'-segments; a cloudId from a different Elastic deployment format; a corrupted/truncated Base64 that decodes to garbage without the expected separators.

Common situations: Wrong cloudId copied (e.g. from a Kibana-only or APM deployment); Base64 string trimmed or padded incorrectly; using a placeholder/example cloudId that is not a real one.

Related errors


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