SonarSource/sonarqube · error · IllegalStateException

Missing HTTP header 'Location' in redirect of %s

Error message

Missing HTTP header 'Location' in redirect of %s

What it means

HttpConnector.followPostRedirect() re-issues POST requests after an HTTP 3xx redirect, but OkHttp is configured with noRedirectOkHttpClient so the connector must locate the redirect target itself via the 'Location' response header. When a redirect response arrives without that header, the connector cannot build the follow-up request and throws this IllegalStateException. It signals a malformed/non-conformant redirect from the server.

Source

Thrown at sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java:238

  }

  private Response checkRedirect(Response response, RequestWithPayload<?> postRequest) {
    if (List.of(HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_TEMP_REDIRECT, HTTP_PERM_REDIRECT).contains(response.code())) {
      // OkHttpClient does not follow the redirect with the same HTTP method. A POST is
      // redirected to a GET. Because of that the redirect must be manually implemented.
      // See:
      // https://github.com/square/okhttp/blob/07309c1c7d9e296014268ebd155ebf7ef8679f6c/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java#L316
      // https://github.com/square/okhttp/issues/936#issuecomment-266430151
      return followPostRedirect(response, postRequest);
    } else {
      return response;
    }
  }

  private Response followPostRedirect(Response response, RequestWithPayload<?> postRequest) {
    String location = response.header("Location");
    if (location == null) {
      throw new IllegalStateException(format("Missing HTTP header 'Location' in redirect of %s", response.request().url()));
    }
    HttpUrl url = response.request().url().resolve(location);

    // Don't follow redirects to unsupported protocols.
    if (url == null) {
      throw new IllegalStateException(format("Unsupported protocol in redirect of %s to %s", response.request().url(), location));
    }

    Request.Builder redirectRequest = response.request().newBuilder();
    redirectRequest.post(response.request().body());
    response.body().close();
    return doCall(prepareOkHttpClient(noRedirectOkHttpClient, postRequest), redirectRequest.url(url).build());
  }

  /**
   * @since 5.5
   */
  public static Builder newBuilder() {

View on GitHub (pinned to 184c821202)

Solutions

  1. Fix the server/proxy so every 3xx response includes a valid 'Location' header
  2. Call the final (non-redirecting) URL directly to bypass the broken redirect
  3. Inspect the redirecting hop with curl -v and remove/reconfigure the middleware that produces the headerless redirect

Example fix

// before: server sends 302 without Location
res.writeHead(302); res.end();
// after
res.writeHead(302, { Location: '/session/new' }); res.end();
Defensive patterns

Strategy: try-catch

Try / catch

// before calling the WS client you cannot inspect headers, so catch at call site
try {
  wsClient.post(request);
} catch (IllegalStateException e) {
  if (e.getMessage().contains("Missing HTTP header 'Location'")) {
    // fall back to the final URL directly or surface a server/proxy misconfiguration
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: A POST through HttpConnector (doCall/checkRedirect path) receives an HTTP 301/302/303/307/308 response whose headers lack a 'Location' header, so response.header("Location") returns null.

Common situations: Reverse proxies or load balancers emitting incomplete 302 responses; custom server-side redirects that set status but forget Location; misconfigured SSO/auth redirects in front of SonarQube; HTTP intermediaries stripping the header.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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