{"record":{"id":"638058496cbabdd1","repo":"SonarSource/sonarqube","slug":"error-returned-by-bitbucket-cloud-s","errorCode":null,"errorMessage":"Error returned by Bitbucket Cloud: %s","messagePattern":"Error returned by Bitbucket Cloud: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClient.java","lineNumber":143,"sourceCode":"\n  private Token validateAccessToken(String clientId, String clientSecret) {\n    Request request = createAccessTokenRequest(clientId, clientSecret);\n    try (Response response = client.newCall(request).execute()) {\n      if (response.isSuccessful()) {\n        return buildGson().fromJson(response.body().charStream(), Token.class);\n      }\n\n      ErrorDetails errorMsg = getTokenError(response.body(), response.message());\n      if (errorMsg.body != null) {\n        LOG.atInfo().log(() -> String.format(BBC_FAIL_WITH_RESPONSE, response.request().url(), response.code(), errorMsg.body));\n        switch (errorMsg.body) {\n          case \"invalid_grant\":\n            throw new IllegalArgumentException(UNABLE_TO_CONTACT_BBC_SERVERS + \": \" + OAUTH_CONSUMER_NOT_PRIVATE);\n          case \"unauthorized_client\":\n            throw new IllegalArgumentException(UNABLE_TO_CONTACT_BBC_SERVERS + \": \" + UNAUTHORIZED_CLIENT);\n          default:\n            if (errorMsg.parsedErrorMsg != null) {\n              throw new IllegalArgumentException(ERROR_BBC_SERVERS + \": \" + errorMsg.parsedErrorMsg);\n            } else {\n              throw new IllegalArgumentException(UNABLE_TO_CONTACT_BBC_SERVERS);\n            }\n        }\n      } else {\n        LOG.atInfo().log(() -> String.format(BBC_FAIL_WITH_RESPONSE, response.request().url(), response.code(), response.message()));\n      }\n      throw new IllegalArgumentException(UNABLE_TO_CONTACT_BBC_SERVERS);\n\n    } catch (IOException e) {\n      LOG.info(String.format(BBC_FAIL_WITH_ERROR, request.url(), e.getMessage()));\n      throw new IllegalArgumentException(UNABLE_TO_CONTACT_BBC_SERVERS, e);\n    }\n  }\n\n  public RepositoryList searchRepos(String encodedApiTokenCredentials, String workspace, @Nullable String repoName, Integer page, Integer pageSize) {\n    String filterQuery = String.format(\"q=name~\\\"%s\\\"\", repoName != null ? repoName : \"\");\n    HttpUrl url = buildUrl(String.format(\"/repositories/%s?%s&page=%s&pagelen=%s\", workspace, filterQuery, page, pageSize));","sourceCodeStart":125,"sourceCodeEnd":161,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClient.java#L125-L161","documentation":"In validateAccessToken(), the token endpoint returned a non-success HTTP status whose body contained an 'error' string that is neither 'invalid_grant' nor 'unauthorized_client', but a JSON 'error_description' (parsedErrorMsg) was present. The client then throws IllegalArgumentException('Error returned by Bitbucket Cloud: ' + parsedErrorMsg), surfacing Bitbucket's own error description verbatim to the SonarQube admin. It is a pass-through wrapper around whatever OAuth error Bitbucket chose to report.","triggerScenarios":"POST to https://bitbucket.org/site/oauth2/access_token with grant_type=client_credentials and Basic credentials returns a non-2xx response whose JSON body parses to TokenError with a non-null errorDescription and an 'error' value outside {invalid_grant, unauthorized_client} — e.g. 'invalid_request' (missing/malformed parameters), 'invalid_client' variants, or other OAuth errors with descriptions.","commonSituations":"Proxies or gateways rewriting the token request causing invalid_request; consumer misconfigured so Bitbucket rejects the grant with a descriptive message; temporarily returned upstream descriptions during Bitbucket incidents; custom reverse-proxy in front of bitbucket.org altering the request flow.","solutions":["Read the 'Error returned by Bitbucket Cloud: <description>' suffix — it is Bitbucket's own error_description; address the OAuth issue it names","Confirm the token request is exactly grant_type=client_credentials with the consumer's Key/Secret as HTTP Basic (no extra or missing parameters)","Check the Bitbucket consumer is a private consumer in the correct workspace with Account/Repository/PullRequest read scopes","Check Bitbucket Cloud status for ongoing incidents and retry if the description suggests a transient/server-side condition","Inspect the server INFO log line 'Bitbucket Cloud API call to [...] failed with <code> http code' for the exact HTTP status"],"exampleFix":"// before: body {\"error\":\"invalid_request\",\"error_description\":\"grant_type not supported\"}\n// (thrown from validateAccessToken default branch)\n// after: send the exact expected form\nRequestBody body = new FormBody.Builder().add(\"grant_type\", \"client_credentials\").build();\nRequest req = new Request.Builder().url(tokenUrl).header(\"Authorization\", Credentials.basic(clientId, clientSecret)).post(body).build();","handlingStrategy":"try-catch","validationCode":"// Pre-flight the exact token request and inspect the OAuth error_description\n// curl -s -X POST -u \"$KEY\":\"$SECRET\" -d grant_type=client_credentials \\\n//   https://bitbucket.org/site/oauth2/access_token\n// The JSON 'error_description' field is what will appear after 'Error returned by Bitbucket Cloud: '\nif (tokenResponse.contains(\"\\\"error_description\\\"\")) {\n  String desc = extractJsonField(tokenResponse, \"error_description\");\n  throw new ConfigurationException(\"Bitbucket rejected the grant: \" + desc);\n}","typeGuard":null,"tryCatchPattern":"try {\n  client.validate(clientId, clientSecret, workspace);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().startsWith(\"Error returned by Bitbucket Cloud:\")) {\n    // Bitbucket's own error_description follows — surface it verbatim to the admin\n    log.error(\"Bitbucket OAuth error: {}\", e.getMessage());\n  }\n  throw e;\n}","preventionTips":["Read the message suffix — it is Bitbucket's error_description and names the exact OAuth problem","Keep the token request minimal: only grant_type=client_credentials; extra/missing params trigger invalid_request","Verify no reverse proxy is intercepting bitbucket.org from the SonarQube server","Check Bitbucket Cloud status for transient upstream errors before changing configuration"],"tags":["bitbucket","oauth","http-client","api-error"],"backgroundTag":"api-error-response","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}