{"record":{"id":"b0720d670bd97142","repo":"apple/pkl","slug":"httptoomanyredirects","errorCode":"httpTooManyRedirects","errorMessage":"httpTooManyRedirects: ${max}","messagePattern":"httpTooManyRedirects: (.+?)","errorType":"exception","errorClass":"HttpClientException","httpStatus":null,"severity":"error","filePath":"pkl-core/src/main/java/org/pkl/core/http/RequestRewritingClient.java","lineNumber":126,"sourceCode":"  private <T> HttpResponse<T> doSend(\n      HttpRequest request,\n      BodyHandler<T> responseBodyHandler,\n      HttpRequestChecker httpRequestChecker)\n      throws SecurityManagerException, IOException {\n    var redirectCount = 0;\n    var currentRequestUri = rewriteUri(request.uri());\n    var currentRequest = rewriteRequest(request, currentRequestUri);\n    while (true) {\n      httpRequestChecker.check(currentRequestUri);\n      var response = delegate.send(currentRequest, responseBodyHandler, httpRequestChecker);\n      if (!HttpUtils.isRedirectStatusCode(response.statusCode())) {\n        return response;\n      }\n      if (response.body() instanceof Closeable closeable) {\n        closeable.close();\n      }\n      if (redirectCount >= MAX_HTTP_REDIRECTS) {\n        throw new HttpClientException(\n            ErrorMessages.create(\"httpTooManyRedirects\", MAX_HTTP_REDIRECTS));\n      }\n      var location = response.headers().firstValue(\"Location\");\n      if (location.isEmpty()) {\n        throw new HttpClientException(\n            ErrorMessages.create(\"httpRedirectNoLocation\", currentRequestUri));\n      }\n      URI redirectUri;\n      try {\n        redirectUri = currentRequestUri.resolve(location.get());\n      } catch (IllegalArgumentException e) {\n        throw new HttpClientException(\n            ErrorMessages.create(\"httpRedirectInvalidUri\", currentRequestUri, location.get()));\n      }\n      if (currentRequestUri.getScheme().equalsIgnoreCase(\"https\")\n          && redirectUri.getScheme().equalsIgnoreCase(\"http\")) {\n        throw new HttpClientException(\n            ErrorMessages.create(\"httpRedirectCannotDowngrade\", currentRequestUri, redirectUri));","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/apple/pkl/blob/f3efcbfc9b60d30053b0536d664948d7aa1b8673/pkl-core/src/main/java/org/pkl/core/http/RequestRewritingClient.java#L108-L144","documentation":"Pkl's HTTP client followed the maximum number of HTTP redirects (MAX_HTTP_REDIRECTS) without reaching a final response. doSend tracks redirectCount across responses and throws httpTooManyRedirects when the limit is reached, as a guard against redirect loops.","triggerScenarios":"A Pkl `import`/module fetch over HTTP encounters a server (or chain of servers) whose responses keep redirecting — typically a redirect loop (A -> B -> A) or a chain longer than MAX_HTTP_REDIRECTS. doSend throws after closing each interim response body.","commonSituations":"A misconfigured web server redirecting between trailing-slash and non-trailing-slash URLs forever, http<->https ping-pong caused by conflicting TLS settings, a load balancer loop, or an extremely long redirect chain.","solutions":["Open the URL in curl (`curl -IL <url>`) and inspect the Location headers to find the redirect loop.","Fix the loop on the server side (rewrite rules, trailing-slash handling, http-to-https configuration).","If the target moved, update the Pkl import/dependency URL to the final destination.","Check for a proxy rewriting URLs into a cycle (see no-proxy/proxy config).","As a workaround, serve the content at a stable, non-redirecting URL."],"exampleFix":"// before (nginx)\nrewrite ^/pkg/$ /pkg permanent;   # /pkg -> /pkg/ -> /pkg loop\n// after (nginx)\nlocation /pkg { try_files $uri $uri/ =404; }","handlingStrategy":"retry","validationCode":"HttpURLConnection c = (HttpURLConnection) URI.create(targetUrl).toURL().openConnection();\nc.setInstanceFollowRedirects(false);\nint code = c.getResponseCode();\nSet<String> seen = new HashSet<>();\nwhile (300 <= code && code < 400) {\n  String loc = c.getHeaderField(\"Location\");\n  if (loc == null || !seen.add(loc)) throw new IllegalStateException(\"Redirect loop at \" + loc);\n  c = (HttpURLConnection) URI.create(loc).toURL().openConnection();\n  code = c.getResponseCode();\n}","typeGuard":null,"tryCatchPattern":"try {\n  // fetch module via Pkl\n} catch (HttpClientException e) {\n  if (e.getMessage().startsWith(\"httpTooManyRedirects\")) {\n    // diagnose loop with curl -IL, point the import at the final URL\n  }\n}","preventionTips":["Curl -IL your import URLs in CI to detect redirect loops early.","Pin dependencies to stable, non-redirecting URLs.","Fix trailing-slash and http->https rewrite loops on servers you control.","Check load balancer redirect rules when a URL bounces between hosts."],"tags":["http","redirects","loop","network"],"backgroundTag":"http-error-response","analyzedSha":"f3efcbfc9b60d30053b0536d664948d7aa1b8673","analyzedAt":"2026-09-08T13:10:45.570Z","contentChangedAt":"2026-09-08T13:10:45.570Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}