quarkusio/quarkus · error · SpiffeConnectionException
JWT-SVID 'aud' array element at index ${i} is not a string:$
Error message
JWT-SVID 'aud' array element at index ${i} is not a string:${value} What it means
When the 'aud' claim is a JSON array, every element must be a string per JWT spec. The client iterates the array and throws SpiffeConnectionException at the first non-string element, since audiences must be comparable to the requested set of strings.
Source
Thrown at extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeClientImpl.java:246
String sub = payload.getString("sub");
SpiffeValidator.validateSpiffeId(sub);
if (!sub.equals(svid.getSpiffeId())) {
throw new SpiffeConnectionException(
"JWT-SVID proto SPIFFE ID does not match the 'sub' claim; proto: " + svid.getSpiffeId() + ", sub: " + sub);
}
Object aud = payload.getValue("aud");
if (aud == null) {
throw new SpiffeConnectionException("JWT-SVID from SPIRE agent is missing the required 'aud' claim");
}
final Set<String> audience;
if (aud instanceof JsonArray audienceAsArray) {
audience = new HashSet<>(audienceAsArray.size());
for (int i = 0; i < audienceAsArray.size(); i++) {
if (audienceAsArray.getValue(i) instanceof String audienceAsString) {
audience.add(audienceAsString);
} else {
throw new SpiffeConnectionException(
"JWT-SVID 'aud' array element at index " + i + " is not a string:" + audienceAsArray.getValue(i));
}
}
} else if (aud instanceof String audienceAsString) {
audience = Set.of(audienceAsString);
} else {
throw new SpiffeConnectionException(
"JWT-SVID 'aud' claim is not a string or array of strings");
}
if (!audience.containsAll(requestedAudiences)) {
throw new SpiffeConnectionException(
"JWT-SVID 'aud' claim does not contain the requested audiences; requested: "
+ requestedAudiences + ", received: " + audience);
}
if (audience.size() != requestedAudiences.size()) {
throw new SpiffeConnectionException(
"JWT-SVID 'aud' claim contains unexpected extra audiences; requested: "
+ requestedAudiences + ", received: " + audience);View on GitHub (pinned to e1c734241f)
Solutions
- Correct the token source so all aud array elements are strings
- Replace stubbed JWTs with real ones fetched via spire-agent api fetch jwt
- Check for middleware/proxies that decode and re-encode JWT payloads with altered types
Example fix
// before
{"aud":["https://api.example.com", 42]}
// after
{"aud":["https://api.example.com", "https://other.example.com"]} Defensive patterns
Strategy: type-guard
Type guard
static boolean audClaimIsValid(Object aud) {
if (aud instanceof String) return true;
if (aud instanceof JsonArray arr) {
for (int i = 0; i < arr.size(); i++) {
if (!(arr.getValue(i) instanceof String)) return false;
}
return true;
}
return false;
} Try / catch
try {
return spiffeClient.getWorkloadJsonWebToken(audiences).await().indefinitely();
} catch (SpiffeConnectionException e) {
if (e.getMessage().contains("'aud' array element")) {
// fix token producer / replace stubs
}
throw e;
} Prevention
- Ensure test fixtures emit string-only aud arrays
- Do not decode/re-encode JWT payloads in middleware
- Lint JWT payloads used in tests before use
When it happens
Trigger: Decoded payload contains aud as an array with numeric/boolean/object/null elements — typically from a hand-built or corrupted token rather than a real SPIRE-issued SVID.
Common situations: Test fixtures with wrongly typed audience values; JSON encoding mistakes when replaying captured tokens; intermediary services rewriting the token payload.
Related errors
- JWT-SVID 'aud' claim is not a string or array of strings
- JWT-SVID 'aud' claim does not contain the requested audience
- JWT-SVID 'aud' claim contains unexpected extra audiences; re
- 'credentials.jwt.source' is set to 'spiffe-jwt', but no audi
- JWT-SVID from SPIRE agent has no token
AI-assisted analysis of quarkusio/quarkus@e1c734241f (2026-09-05).
Data as JSON: /api/errors/5894aed50669cb2f.
Report an issue: GitHub.