{"record":{"id":"f80f875dd56b7eaf","repo":"apache/hadoop","slug":"received-invalid-http-response-statuscode-text-f80f87","errorCode":null,"errorMessage":"Received invalid http response: {statusCode}, text = {text}","messagePattern":"Received invalid http response: (.+?), text = (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/web/oauth2/CredentialBasedAccessTokenProvider.java","lineNumber":124,"sourceCode":"  void refresh() throws IOException {\n    final List<NameValuePair> pairs = new ArrayList<>();\n    pairs.add(new BasicNameValuePair(CLIENT_SECRET, getCredential()));\n    pairs.add(new BasicNameValuePair(GRANT_TYPE, CLIENT_CREDENTIALS));\n    pairs.add(new BasicNameValuePair(CLIENT_ID, clientId));\n    final RequestConfig config = RequestConfig.custom()\n        .setConnectTimeout(URLConnectionFactory.DEFAULT_SOCKET_TIMEOUT)\n        .setConnectionRequestTimeout(URLConnectionFactory.DEFAULT_SOCKET_TIMEOUT)\n        .setSocketTimeout(URLConnectionFactory.DEFAULT_SOCKET_TIMEOUT)\n        .build();\n    try (CloseableHttpClient client =\n             HttpClientBuilder.create().setDefaultRequestConfig(config).build()) {\n      final HttpPost httpPost = new HttpPost(refreshURL);\n      httpPost.setEntity(new UrlEncodedFormEntity(pairs, StandardCharsets.UTF_8));\n      httpPost.setHeader(HttpHeaders.CONTENT_TYPE, URLENCODED);\n      try (CloseableHttpResponse response = client.execute(httpPost)) {\n        final int statusCode = response.getStatusLine().getStatusCode();\n        if (statusCode != HttpStatus.SC_OK) {\n          throw new IllegalArgumentException(\n              \"Received invalid http response: \" + statusCode + \", text = \" +\n                  EntityUtils.toString(response.getEntity()));\n        }\n        Map<?, ?> responseBody = JsonSerialization.mapReader().readValue(\n            EntityUtils.toString(response.getEntity()));\n\n        String newExpiresIn = responseBody.get(EXPIRES_IN).toString();\n        timer.setExpiresIn(newExpiresIn);\n\n        accessToken = responseBody.get(ACCESS_TOKEN).toString();\n      }\n    } catch (RuntimeException e) {\n      throw new IOException(\"Unable to obtain access token from credential\", e);\n    } catch (Exception e) {\n      throw new IOException(\"Unable to obtain access token from credential\", e);\n    }\n  }\n}","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/web/oauth2/CredentialBasedAccessTokenProvider.java#L106-L142","documentation":"CredentialBasedAccessTokenProvider.refresh posts the client credential to dfs.webhdfs.oauth2.refresh.url to obtain an access token; any HTTP status other than 200 throws IllegalArgumentException embedding the status code and full response text. This is the client-credentials grant variant of the same check as ConfRefreshTokenBasedAccessTokenProvider (message and flow identical, provider differs). The embedded body carries the IdP's exact error (invalid_client, invalid_request, unauthorized_client, 5xx...).","triggerScenarios":"refresh() running on token expiry when the token endpoint replies non-200: wrong or expired dfs.webhdfs.oauth2.credential secret, wrong dfs.webhdfs.oauth2.client.id, endpoint URL typo, or IdP outage (503).","commonSituations":"Credential rotated in the IdP but dfs.webhdfs.oauth2.credential in core-site.xml not updated; app not granted the OAuth2 client-credentials flow (unauthorized_client); environment-specific URLs mixed up; AAD/Google endpoint format changes.","solutions":["Read the response text inside the exception message and act on the OAuth error code: invalid_client -> update dfs.webhdfs.oauth2.credential / client id; unauthorized_client -> grant the flow to the app","Confirm dfs.webhdfs.oauth2.refresh.url and dfs.webhdfs.oauth2.client.id match the IdP app registration","Validate the credential independently with curl -d 'grant_type=client_credentials&client_id=...&client_secret=...' <url>","Rotate and redistribute the credential if it has expired or been revoked"],"exampleFix":"<!-- before -->\n<property><name>dfs.webhdfs.oauth2.credential</name><value>expired-secret</value></property>\n<!-- after: current secret from the IdP app registration -->\n<property><name>dfs.webhdfs.oauth2.credential</name><value>current-secret</value></property>","handlingStrategy":"try-catch","validationCode":"assertNotNull(conf.get(\"dfs.webhdfs.oauth2.credential\"), \"credential\");\nassertNotNull(conf.get(\"dfs.webhdfs.oauth2.client.id\"), \"client id\");\nassertNotNull(conf.get(\"dfs.webhdfs.oauth2.refresh.url\"), \"token url\");","typeGuard":null,"tryCatchPattern":"try {\n  fs.open(p);\n} catch (IOException e) {\n  Throwable root = e.getCause() != null ? e.getCause() : e;\n  if (root instanceof IllegalArgumentException\n      && root.getMessage().contains(\"Received invalid http response\")) {\n    // status + body are in the message: invalid_client -> rotate credential,\n    // 5xx -> IdP outage, retry later\n  }\n}","preventionTips":["Rotate client credentials on a schedule and update dfs.webhdfs.oauth2.credential atomically","Run a client_credentials curl test in CI against the real IdP","Alert on refresh failures so credential rot is fixed before jobs die"],"tags":["oauth2","webhdfs","http-status","client-credentials"],"backgroundTag":"oauth2-token-refresh-failed","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}