{"record":{"id":"5894aed50669cb2f","repo":"quarkusio/quarkus","slug":"jwt-svid-aud-array-element-at-index-i-is-not","errorCode":null,"errorMessage":"JWT-SVID 'aud' array element at index ${i} is not a string:${value}","messagePattern":"JWT-SVID 'aud' array element at index (.+?) is not a string:(.+?)","errorType":"exception","errorClass":"SpiffeConnectionException","httpStatus":null,"severity":"error","filePath":"extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeClientImpl.java","lineNumber":246,"sourceCode":"        String sub = payload.getString(\"sub\");\n        SpiffeValidator.validateSpiffeId(sub);\n        if (!sub.equals(svid.getSpiffeId())) {\n            throw new SpiffeConnectionException(\n                    \"JWT-SVID proto SPIFFE ID does not match the 'sub' claim; proto: \" + svid.getSpiffeId() + \", sub: \" + sub);\n        }\n\n        Object aud = payload.getValue(\"aud\");\n        if (aud == null) {\n            throw new SpiffeConnectionException(\"JWT-SVID from SPIRE agent is missing the required 'aud' claim\");\n        }\n        final Set<String> audience;\n        if (aud instanceof JsonArray audienceAsArray) {\n            audience = new HashSet<>(audienceAsArray.size());\n            for (int i = 0; i < audienceAsArray.size(); i++) {\n                if (audienceAsArray.getValue(i) instanceof String audienceAsString) {\n                    audience.add(audienceAsString);\n                } else {\n                    throw new SpiffeConnectionException(\n                            \"JWT-SVID 'aud' array element at index \" + i + \" is not a string:\" + audienceAsArray.getValue(i));\n                }\n            }\n        } else if (aud instanceof String audienceAsString) {\n            audience = Set.of(audienceAsString);\n        } else {\n            throw new SpiffeConnectionException(\n                    \"JWT-SVID 'aud' claim is not a string or array of strings\");\n        }\n        if (!audience.containsAll(requestedAudiences)) {\n            throw new SpiffeConnectionException(\n                    \"JWT-SVID 'aud' claim does not contain the requested audiences; requested: \"\n                            + requestedAudiences + \", received: \" + audience);\n        }\n        if (audience.size() != requestedAudiences.size()) {\n            throw new SpiffeConnectionException(\n                    \"JWT-SVID 'aud' claim contains unexpected extra audiences; requested: \"\n                            + requestedAudiences + \", received: \" + audience);","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/quarkusio/quarkus/blob/e1c734241f34c7919086ceb4c9262b4a58f6de44/extensions/spiffe-client/runtime/src/main/java/io/quarkus/spiffe/client/runtime/internal/SpiffeClientImpl.java#L228-L264","documentation":"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.","triggerScenarios":"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.","commonSituations":"Test fixtures with wrongly typed audience values; JSON encoding mistakes when replaying captured tokens; intermediary services rewriting the token payload.","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"],"exampleFix":"// before\n{\"aud\":[\"https://api.example.com\", 42]}\n// after\n{\"aud\":[\"https://api.example.com\", \"https://other.example.com\"]}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"static boolean audClaimIsValid(Object aud) {\n    if (aud instanceof String) return true;\n    if (aud instanceof JsonArray arr) {\n        for (int i = 0; i < arr.size(); i++) {\n            if (!(arr.getValue(i) instanceof String)) return false;\n        }\n        return true;\n    }\n    return false;\n}","tryCatchPattern":"try {\n    return spiffeClient.getWorkloadJsonWebToken(audiences).await().indefinitely();\n} catch (SpiffeConnectionException e) {\n    if (e.getMessage().contains(\"'aud' array element\")) {\n        // fix token producer / replace stubs\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["spiffe","jwt","type-mismatch","aud-claim"],"backgroundTag":"jwt-claim-type-invalid","analyzedSha":"e1c734241f34c7919086ceb4c9262b4a58f6de44","analyzedAt":"2026-09-05T17:01:29.979Z","contentChangedAt":"2026-09-05T17:01:29.979Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}