SonarSource/sonarqube · error · BitbucketServerException

Error 404. The requested Bitbucket server is unreachable.

Error message

Error 404. The requested Bitbucket server is unreachable.

What it means

BitbucketServerRestClient.handleHttpErrorIfAny maps HTTP response codes to exceptions. When the Bitbucket Server REST call returns 404 (HTTP_NOT_FOUND), it throws BitbucketServerException(404, "Error 404. The requested Bitbucket server is unreachable."). Despite the wording, it means the server responded but the requested path/resource was not found — most often a wrong URL, wrong project/repo slug, or a proxy stripping the path.

Source

Thrown at server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucketserver/BitbucketServerRestClient.java:190

  protected static void validateResponseBody(boolean isSuccessful, String bodyString) {
    if (isSuccessful) {
      try {
        buildGson().fromJson(bodyString, Object.class);
      } catch (JsonParseException e) {
        LOG.info(UNEXPECTED_RESPONSE_FROM_BITBUCKET_SERVER + " : [{}]", bodyString);
        throw new IllegalArgumentException(UNEXPECTED_RESPONSE_FROM_BITBUCKET_SERVER, e);
      }
    }
  }

  protected static void handleHttpErrorIfAny(boolean isSuccessful, int httpCode, String bodyString) {
    if (!isSuccessful) {
      String errorMessage = getErrorMessage(bodyString);
      LOG.info(UNABLE_TO_CONTACT_BITBUCKET_SERVER + ": {} {}", httpCode, errorMessage);
      if (httpCode == HTTP_UNAUTHORIZED) {
        throw new BitbucketServerException(HTTP_UNAUTHORIZED, "Invalid personal access token");
      } else if (httpCode == HTTP_NOT_FOUND) {
        throw new BitbucketServerException(HTTP_NOT_FOUND, "Error 404. The requested Bitbucket server is unreachable.");
      }
      throw new IllegalArgumentException(UNABLE_TO_CONTACT_BITBUCKET_SERVER);
    }
  }

  protected static boolean equals(@Nullable MediaType first, @Nullable MediaType second) {
    String s1 = convertMediaTypeToString(first);
    String s2 = convertMediaTypeToString(second);
    return s1 != null && s1.equals(s2);
  }

  private static String convertMediaTypeToString(@Nullable MediaType mediaType) {
    return Optional.ofNullable(mediaType)
      .map(MediaType::toString)
      .map(s -> s.toLowerCase(ENGLISH).replace(" ", ""))
      .orElse(null);
  }

View on GitHub (pinned to 184c821202)

Solutions

  1. Verify the Bitbucket Server URL in Administration > ALM Integrations > Bitbucket Server: it must be the server base URL including the context path (e.g. https://bitbucket.example.com/bitbucket), with no trailing path to the API
  2. Check that the project/repo slug used by the DevOps platform binding exactly matches the Bitbucket repository slug
  3. Test the URL manually: curl -k -u <user>:<token> <url>/rest/api/1.0/projects — if this 404s, the URL is wrong
  4. Confirm a proxy/firewall is not returning its own 404 page; inspect the errorMessage logged by the client for the actual 404 body

Example fix

// before (wrong: includes API path or omits context path)
almSetting.setUrl("https://bitbucket.example.com/rest/api/1.0");
// after
correctUrl = "https://bitbucket.example.com" + (hasContextPath ? "/bitbucket" : "");
almSetting.setUrl(correctUrl);
Defensive patterns

Strategy: try-catch

Validate before calling

// Java: pre-check before calling the client
URL u = new URL(bitbucketServerUrl);
HttpURLConnection c = (HttpURLConnection) new URL(u, "/rest/api/1.0/projects?limit=1").openConnection();
c.setRequestProperty("Authorization", "Bearer " + token);
if (c.getResponseCode() == 404) throw new IllegalStateException("Wrong Bitbucket Server URL or missing context path");

Type guard

// Java: sanity-check the configured URL shape before calling
static boolean isPlausibleBitbucketUrl(String url) {
  try {
    URI uri = new URI(url);
    return uri.getScheme() != null && (uri.getScheme().equals("https") || uri.getScheme().equals("http")) && uri.getHost() != null;
  } catch (URISyntaxException e) { return false; }
}

Try / catch

try {
  client.getRepo(projectKey, repoSlug);
} catch (BitbucketServerException e) {
  if (e.getStatus() == 404) {
    // wrong URL, context path, or repo slug — re-check configuration and binding
    throw new ConfigurationException("Bitbucket server URL or repository binding is wrong: " + e.getMessage());
  }
  throw e;
}

Prevention

When it happens

Trigger: Any REST call made through getBodyString (e.g. validateUrl, validateToken, project/repo lookups during ALM import or PR decoration) where Bitbucket Server answers HTTP 404.

Common situations: Typo in the configured Bitbucket Server URL (e.g. missing or extra context path like /bitbucket); repository was renamed/deleted or the repo slug case is wrong; SonarQube pointed at the wrong base URL so /rest/api/* paths 404; a reverse proxy returns 404 for unknown hosts; SonarQube configured against Bitbucket Cloud instead of Bitbucket Server.

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


AI-assisted analysis of SonarSource/sonarqube@184c821202 (2026-09-09). Data as JSON: /api/errors/8097e74f9d05e755. Report an issue: GitHub.