{"record":{"id":"54639290da11cd1a","repo":"SonarSource/sonarqube","slug":"missing-http-header-location-in-redirect-of-s","errorCode":null,"errorMessage":"Missing HTTP header 'Location' in redirect of %s","messagePattern":"Missing HTTP header 'Location' in redirect of (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java","lineNumber":238,"sourceCode":"  }\n\n  private Response checkRedirect(Response response, RequestWithPayload<?> postRequest) {\n    if (List.of(HTTP_MOVED_PERM, HTTP_MOVED_TEMP, HTTP_TEMP_REDIRECT, HTTP_PERM_REDIRECT).contains(response.code())) {\n      // OkHttpClient does not follow the redirect with the same HTTP method. A POST is\n      // redirected to a GET. Because of that the redirect must be manually implemented.\n      // See:\n      // https://github.com/square/okhttp/blob/07309c1c7d9e296014268ebd155ebf7ef8679f6c/okhttp/src/main/java/okhttp3/internal/http/RetryAndFollowUpInterceptor.java#L316\n      // https://github.com/square/okhttp/issues/936#issuecomment-266430151\n      return followPostRedirect(response, postRequest);\n    } else {\n      return response;\n    }\n  }\n\n  private Response followPostRedirect(Response response, RequestWithPayload<?> postRequest) {\n    String location = response.header(\"Location\");\n    if (location == null) {\n      throw new IllegalStateException(format(\"Missing HTTP header 'Location' in redirect of %s\", response.request().url()));\n    }\n    HttpUrl url = response.request().url().resolve(location);\n\n    // Don't follow redirects to unsupported protocols.\n    if (url == null) {\n      throw new IllegalStateException(format(\"Unsupported protocol in redirect of %s to %s\", response.request().url(), location));\n    }\n\n    Request.Builder redirectRequest = response.request().newBuilder();\n    redirectRequest.post(response.request().body());\n    response.body().close();\n    return doCall(prepareOkHttpClient(noRedirectOkHttpClient, postRequest), redirectRequest.url(url).build());\n  }\n\n  /**\n   * @since 5.5\n   */\n  public static Builder newBuilder() {","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/sonar-ws/src/main/java/org/sonarqube/ws/client/HttpConnector.java#L220-L256","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fix the server/proxy so every 3xx response includes a valid 'Location' header","Call the final (non-redirecting) URL directly to bypass the broken redirect","Inspect the redirecting hop with curl -v and remove/reconfigure the middleware that produces the headerless redirect"],"exampleFix":"// before: server sends 302 without Location\nres.writeHead(302); res.end();\n// after\nres.writeHead(302, { Location: '/session/new' }); res.end();","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// before calling the WS client you cannot inspect headers, so catch at call site\ntry {\n  wsClient.post(request);\n} catch (IllegalStateException e) {\n  if (e.getMessage().contains(\"Missing HTTP header 'Location'\")) {\n    // fall back to the final URL directly or surface a server/proxy misconfiguration\n  } else {\n    throw e;\n  }\n}","preventionTips":["Verify proxies/gateways in front of SonarQube emit conformant 3xx responses with Location","Prefer configuring the client with the final URL to avoid redirect chains","Test redirect behavior with curl -i when routing changes are deployed"],"tags":["http","redirect","network","ws-client"],"backgroundTag":"unexpected-api-response-shape","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"}