{"record":{"id":"afba03775cd8989f","repo":"apache/pulsar","slug":"cannot-obtain-authorization-metadata-from-metada","errorCode":null,"errorMessage":"Cannot obtain authorization metadata from ${metadataUrl}","messagePattern":"Cannot obtain authorization metadata from (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java","lineNumber":117,"sourceCode":"     * Resolves the authorization metadata.\n     *\n     * @return metadata\n     * @throws IOException if the metadata could not be resolved.\n     */\n    public Metadata resolve() throws IOException {\n\n        try {\n            HttpRequest request = HttpRequest.builder(HttpRequest.Method.GET, URI.create(metadataUrl.toString()))\n                    .header(\"Accept\", \"application/json\")\n                    .build();\n            HttpResponse response = httpClient.execute(request).get();\n            return this.objectReader.readValue(response.body());\n\n        } catch (IOException | InterruptedException | ExecutionException e) {\n            if (e instanceof InterruptedException) {\n                Thread.currentThread().interrupt();\n            }\n            throw new IOException(\"Cannot obtain authorization metadata from \" + metadataUrl, e);\n        }\n    }\n}\n","sourceCodeStart":99,"sourceCodeEnd":121,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/auth/oauth2/protocol/DefaultMetadataResolver.java#L99-L121","documentation":"DefaultMetadataResolver.resolve fetches the OIDC authorization-server metadata document from metadataUrl and deserializes it. If fetching fails (IOException, thread interrupted, or the async execution fails), this IOException is thrown wrapping the cause. The library could not obtain the discovery document needed to locate the token endpoint.","triggerScenarios":"resolve() issues an HTTP GET to the issuer's well-known metadata URL and: DNS/connection fails, TLS handshake fails, the IdP returns a non-200 body that can't be read, the response is empty/invalid, or the waiting thread is interrupted.","commonSituations":"Wrong issuerUrl so the metadata 404s or returns HTML; IdP unreachable from the client network; proxy/firewall blocking HTTPS; expired IdP TLS certificate rejected by the client trust store; IdP outage.","solutions":["Verify metadataUrl is reachable: curl <issuer>/.well-known/openid-configuration and confirm valid JSON comes back.","Fix issuerUrl so it points to the actual IdP issuer (no typos, correct tenant path).","Check network path: proxies, firewalls, DNS, and trust store for the IdP's TLS certificate.","Inspect the wrapped cause (getCause()) for the specific transport failure."],"exampleFix":"// before\nString issuer = \"https://auth.example.com/realms/typo-realm\"; // metadata 404s\n// after\nString issuer = \"https://auth.example.com/realms/my-realm\"; // valid discovery doc","handlingStrategy":"try-catch","validationCode":"// pre-check discovery reachability before wiring the client\nHttpRequest req = HttpRequest.newBuilder(URI.create(issuerUrl + \"/.well-known/openid-configuration\")).GET().build();\nHttpResponse<String> resp = HttpClient.newHttpClient().send(req, HttpResponse.BodyHandlers.ofString());\nif (resp.statusCode() != 200 || !resp.body().trim().startsWith(\"{\")) {\n    throw new IOException(\"Discovery metadata not reachable/invalid at \" + req.uri());\n}","typeGuard":null,"tryCatchPattern":"try {\n    client = AuthenticationFactoryOAuth2.clientCredentials(issuerUrl, credFile, audience);\n} catch (IOException e) {\n    if (e.getMessage().startsWith(\"Cannot obtain authorization metadata\")) {\n        // wrapped cause has the transport failure: DNS, TLS, interrupt, etc.\n        throw new RuntimeException(\"Cannot reach OIDC discovery at issuer; cause: \" + e.getCause(), e);\n    }\n    throw e;\n}","preventionTips":["curl <issuer>/.well-known/openid-configuration in the deployment environment before rollout.","Confirm the issuerUrl matches the IdP's advertised issuer exactly (scheme, host, tenant path).","Check proxy/firewall/DNS and add the IdP's TLS cert to the trust store if self-signed.","Monitor IdP health to distinguish outages from config mistakes."],"tags":["oauth2","openid-connect","discovery","network","io","pulsar-client"],"backgroundTag":"discovery-metadata-unavailable","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}