elastic/elasticsearch · error · IllegalStateException
STS AssumeRoleWithWebIdentity response did not include crede
Error message
STS AssumeRoleWithWebIdentity response did not include credentials
What it means
toCached converts the STS AssumeRoleWithWebIdentityResponse into a Cached entry. AWS SDK v2 allows response.credentials() to be null on a malformed or partial response; the provider treats a null Credentials object as an illegal state (not a retryable client error).
Source
Thrown at libs/workload-identity-aws/src/main/java/org/elasticsearch/workload/identity/aws/AsyncWebIdentityCredentialsProvider.java:198
private CompletableFuture<String> requestToken() {
CompletableFuture<String> future = new CompletableFuture<>();
ActionListener.run(ActionListener.<String>wrap(future::complete, future::completeExceptionally), tokenSupplier::accept);
return future;
}
private CompletableFuture<AssumeRoleWithWebIdentityResponse> requestCredentials(String token) {
AssumeRoleWithWebIdentityRequest request = AssumeRoleWithWebIdentityRequest.builder()
.roleArn(roleArn)
.roleSessionName(roleSessionName)
.webIdentityToken(token)
.build();
return stsAsyncClient.assumeRoleWithWebIdentity(request);
}
private Cached toCached(AssumeRoleWithWebIdentityResponse response) {
Credentials credentials = response.credentials();
if (credentials == null) {
throw new IllegalStateException("STS AssumeRoleWithWebIdentity response did not include credentials");
}
Instant expiry = credentials.expiration();
if (expiry == null) {
throw new IllegalStateException("STS AssumeRoleWithWebIdentity response did not include a credential expiry");
}
Instant now = clock.instant();
if (expiry.isAfter(now) == false) {
throw new IllegalStateException("STS returned credentials that are already expired at [" + expiry + "] (now [" + now + "])");
}
AwsSessionCredentials sessionCredentials = AwsSessionCredentials.builder()
.accessKeyId(credentials.accessKeyId())
.secretAccessKey(credentials.secretAccessKey())
.sessionToken(credentials.sessionToken())
.expirationTime(expiry)
.build();
return new Cached(sessionCredentials, expiry.minus(prefetchTime), expiry.minus(staleTime));
}
View on GitHub (pinned to db6a809a66)
Solutions
- Inspect the full STS response logging / SDK metrics to see why Credentials was absent
- Verify the IAM trust policy on the role permits sts:AssumeRoleWithWebIdentity for the caller
- If using a test stub, ensure the mocked response includes a non-null Credentials
- File an issue if STS genuinely returns 200 with null Credentials - that indicates an upstream fault
Example fix
// before (mock)
when(sts.assumeRoleWithWebIdentity(req)).thenReturn(AssumeRoleWithWebIdentityResponse.builder().build());
// after
when(sts.assumeRoleWithWebIdentity(req)).thenReturn(
AssumeRoleWithWebIdentityResponse.builder()
.credentials(Credentials.builder().accessKeyId("k").secretAccessKey("s").sessionToken("t").expiration(Instant.now().plusSeconds(900)).build())
.build()); Defensive patterns
Strategy: try-catch
Validate before calling
AssumeRoleWithWebIdentityResponse resp = requestCredentials(token).join();
if (resp.credentials() == null) {
throw new IllegalStateException("STS returned no credentials for role " + roleArn);
} Type guard
static boolean hasCredentials(AssumeRoleWithWebIdentityResponse r) {
return r != null && r.credentials() != null;
} Try / catch
try { toCached(resp); }
catch (IllegalStateException e) { /* log + surface as auth failure */ } Prevention
- Log the full STS response code/message when Credentials is absent
- Validate IAM trust policy in preflight
- In tests, always populate Credentials
When it happens
Trigger: requestCredentials returns a response whose credentials() is null. This is reached after the async STS call completes and the future is being unwrapped.
Common situations: STS returned an error-shaped response without an exception (rare); a misbehaving test double returns a response with no Credentials; an SDK version mismatch where the response shape changed; IAM/permissions edge cases where STS acknowledges the call but returns an empty credentials block.
Related errors
- STS AssumeRoleWithWebIdentity response did not include a cre
- STS returned credentials that are already expired at [${expi
- staleTime must be a positive duration but was [${staleTime}]
- prefetchTime must be a positive duration but was [${prefetch
- prefetchTime [${prefetchTime}] must be greater than or equal
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/3777ef0a4067aed8.
Report an issue: GitHub.