testcontainers/testcontainers-java · error · IllegalStateException

Cannot create service account token in external mode

Error message

Cannot create service account token in external mode

What it means

createKibanaServiceAccountToken runs the elasticsearch-service-tokens tool inside the managed Elasticsearch container, so it requires a managed (non-null) ElasticsearchContainer reference. In external mode — when KibanaContainer is constructed only with an image and points at an already-running ES — there is no container to exec into, so the library throws this IllegalStateException instead of returning a bogus token.

Solutions

  1. Remove the token() call in external mode; instead supply credentials for the external cluster yourself (e.g. generate the service token out-of-band and pass it via withEnv).
  2. Switch to managed mode by constructing KibanaContainer with a started ElasticsearchContainer if you need the library to mint tokens.
  3. Guard the call: only invoke token() when kibana was built in managed mode.

Example fix

// before
KibanaContainer kibana = new KibanaContainer(image); // external mode
String token = kibana.token(); // throws

// after
// external mode: provide config without token()
kibana.withEnv("ELASTICSEARCH_SERVICEACCOUNTTOKEN", System.getenv("MY_KIBANA_TOKEN"));
Defensive patterns

Strategy: type-guard

Type guard

// only fetch tokens in managed mode
boolean isManagedMode(KibanaContainer kibana) {
    // track how you built it
    return kibanaManagedFlag; // set true when constructed with an ElasticsearchContainer
}
if (!isManagedMode(kibana)) return externalTokenFromEnv();

Prevention

When it happens

Trigger: Calling kibana.token() on a KibanaContainer created in external mode (no ElasticsearchContainer passed / elasticsearch == null), e.g. new KibanaContainer(image).withEnv("ELASTICSEARCH_HOSTS", ...) pointing at an external cluster.

Common situations: Copy-pasting managed-mode sample code (which calls token()) into a test that connects to an external/self-hosted Elasticsearch; switching a test from managed to external mode but leaving the token() call in place.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of testcontainers/testcontainers-java@8e549514e3 (2026-09-12). Data as JSON: /api/errors/3a6ca544082fbb1c. Report an issue: GitHub.

Appendix: source

Thrown at modules/elasticsearch/src/main/java/org/testcontainers/elasticsearch/KibanaContainer.java:533

        }
    }

    private static void ensureCompatibleVersion(String esVersion) {
        ComparableVersion comparableVersion = new ComparableVersion(esVersion);
        if (comparableVersion.isLessThan(MINIMUM_SUPPORTED_VERSION)) {
            throw new IllegalArgumentException(
                String.format(
                    "Kibana version %s is not supported. Minimum version is %s",
                    comparableVersion,
                    MINIMUM_SUPPORTED_VERSION
                )
            );
        }
    }

    private String createKibanaServiceAccountToken(String protocol) {
        if (elasticsearch == null) {
            throw new IllegalStateException("Cannot create service account token in external mode");
        }

        String elasticPassword = elasticsearch
            .getEnvMap()
            .getOrDefault("ELASTIC_PASSWORD", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD);

        // Create a unique token name to avoid collisions if the same ES container is reused.
        String tokenName = "tc-kibana-" + Base58.randomString(12);

        String endpoint = protocol + "://localhost:9200/_security/service/elastic/kibana/credential/token/" + tokenName;

        return Unreliables.retryUntilSuccess(
            45,
            TimeUnit.SECONDS,
            () -> {
                String curlTlsArgs = "";
                if ("https".equals(protocol)) {
                    // In managed HTTPS mode, use the Elasticsearch HTTP CA for curl.

View on GitHub (pinned to 8e549514e3)