{"record":{"id":"d7808ba04ca3a144","repo":"alibaba/nacos","slug":"failed-to-parse-jwks","errorCode":null,"errorMessage":"Failed to parse JWKS","messagePattern":"Failed to parse JWKS","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/token/JwksProvider.java","lineNumber":123,"sourceCode":"            throw new IOException(\"JWKS URI is not configured or discovered\");\n        }\n        LOGGER.info(\"Fetching JWKS from: {}\", jwksUri);\n        HttpRequest request = HttpRequest.newBuilder().uri(URI.create(jwksUri))\n            .header(\"Accept\", \"application/json\").GET().build();\n        try {\n            HttpResponse<String> response =\n                httpClient.send(request, HttpResponse.BodyHandlers.ofString());\n            if (response.statusCode() != OidcProtocolConstants.HTTP_STATUS_OK) {\n                throw new IOException(\"Failed to fetch JWKS, status: \" + response.statusCode());\n            }\n            JWKSet result = JWKSet.parse(response.body());\n            LOGGER.info(\"Successfully fetched JWKS with {} keys\", result.getKeys().size());\n            return result;\n        } catch (InterruptedException e) {\n            Thread.currentThread().interrupt();\n            throw new IOException(\"JWKS fetch interrupted\", e);\n        } catch (ParseException e) {\n            throw new IOException(\"Failed to parse JWKS\", e);\n        }\n    }\n    \n    /**\n     * Clear the cached JWK set.\n     */\n    public void clearCache() {\n        jwksCache.invalidateAll();\n    }\n}\n","sourceCodeStart":105,"sourceCodeEnd":134,"githubUrl":"https://github.com/alibaba/nacos/blob/9b989acdf181d00898f2e8839257bb2b2a3cefe3/plugin-default-impl/nacos-oidc-auth-plugin/src/main/java/com/alibaba/nacos/plugin/auth/impl/oidc/token/JwksProvider.java#L105-L134","documentation":"Thrown when JWKSet.parse(body) fails because the JWKS endpoint response is not a valid JWK Set document. The ParseException is wrapped. This means the HTTP call succeeded (200) but the body is not parseable as a JSON Web Key Set.","triggerScenarios":"JWKS endpoint returns 200 but the body is malformed JSON, an HTML page, a JSON object that isn't a JWK Set (missing 'keys' array), or empty.","commonSituations":"jwks_uri points to a non-JWKS endpoint returning 200 (e.g. a UI page); IdP returns a JSON error object instead of a key set; proxy injecting non-JSON content; partial/truncated JWKS body.","solutions":["Inspect the wrapped ParseException cause for the exact parse failure.","curl the jwks_uri and confirm the body is a JSON object with a 'keys' array of JWKs.","Correct jwks_uri in the IdP discovery if it points to the wrong endpoint.","Ensure no proxy returns an HTML/JSON error page with a 200 status at the JWKS URL."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Pre-flight: confirm the JWKS body is a JSON object with a 'keys' array\n// (curl jwks_uri and assert body contains \"keys\":[)","typeGuard":null,"tryCatchPattern":"try {\n    jwksProvider.getJwkSet();\n} catch (IOException e) {\n    if (\"Failed to parse JWKS\".equals(e.getMessage())) {\n        Throwable cause = e.getCause(); // ParseException\n        log.error(\"JWKS body unparseable: {}\", cause == null ? \"?\" : cause.getMessage());\n    }\n    throw e;\n}","preventionTips":["Verify the JWKS endpoint returns a valid JWK Set (object with 'keys' array).","Ensure jwks_uri points to the keys endpoint, not a UI or error page.","Confirm no proxy returns non-JSON content with a 200 status."],"tags":["oidc","jwks","parsing","network"],"backgroundTag":null,"analyzedSha":"9b989acdf181d00898f2e8839257bb2b2a3cefe3","analyzedAt":"2026-08-14T07:17:31.569Z","schemaVersion":2},"datasetVersion":"2026-08-14T10:17:34.591Z"}