{"record":{"id":"b7973f301d03958f","repo":"mislav/hub","slug":"refusing-to-follow-http-d-redirect-for-a-s-reque","errorCode":null,"errorMessage":"refusing to follow HTTP %d redirect for a %s request\nHave your site admin use HTTP %d for this kind of redirect","messagePattern":"refusing to follow HTTP (.+?) redirect for a (.+?) request\nHave your site admin use HTTP (.+?) for this kind of redirect","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"github/http.go","lineNumber":223,"sourceCode":"\n\treturn &http.Client{\n\t\tTransport:     tr,\n\t\tCheckRedirect: checkRedirect,\n\t}\n}\n\nfunc checkRedirect(req *http.Request, via []*http.Request) error {\n\tvar recommendedCode int\n\tswitch req.Response.StatusCode {\n\tcase 301:\n\t\trecommendedCode = 308\n\tcase 302:\n\t\trecommendedCode = 307\n\t}\n\n\torigMethod := via[len(via)-1].Method\n\tif recommendedCode != 0 && !strings.EqualFold(req.Method, origMethod) {\n\t\treturn fmt.Errorf(\n\t\t\t\"refusing to follow HTTP %d redirect for a %s request\\n\"+\n\t\t\t\t\"Have your site admin use HTTP %d for this kind of redirect\",\n\t\t\treq.Response.StatusCode, origMethod, recommendedCode)\n\t}\n\n\t// inherited from stdlib defaultCheckRedirect\n\tif len(via) >= 10 {\n\t\treturn errors.New(\"stopped after 10 redirects\")\n\t}\n\treturn nil\n}\n\nfunc cloneRequest(req *http.Request) *http.Request {\n\tdup := new(http.Request)\n\t*dup = *req\n\tdup.URL, _ = url.Parse(req.URL.String())\n\tdup.Header = make(http.Header)\n\tfor k, s := range req.Header {","sourceCodeStart":205,"sourceCodeEnd":241,"githubUrl":"https://github.com/mislav/hub/blob/5c547ed804368763064e51f3990851e267e88edd/github/http.go#L205-L241","documentation":"checkRedirect customizes Go's http.Client redirect policy: for HTTP 301/302 responses, the client will not follow the redirect if the HTTP method would change (per RFC, 301/302 should keep the method only informally). If the original request was not the method the recommended redirect code (303 for 301, 307 for 302) implies, it refuses and returns this error. This protects tokens/credentials in POST bodies from being silently converted to GETs or resent to a different location.","triggerScenarios":"A POST/PUT/PATCH request to a GitHub Enterprise server that answers 301 or 302, where following the redirect would change the method; checkRedirect is invoked by http.Client as the CheckRedirect hook.","commonSituations":"GitHub Enterprise behind a misconfigured proxy/load balancer issuing 302s to HTTPS or a canonical name for API POSTs; server admin rewriting http->https with a 302 instead of 307/308; wrong base URL (http instead of https) in hub config.","solutions":["Ask the site admin to return 307 (for 302) or 308 (for 301) for method-preserving redirects, as the message instructs.","Change the configured protocol to the redirect target directly: set `protocol: https` (or the canonical host) in ~/.config/hub so no redirect occurs.","Update the API base URL used by the client to the final destination URL.","Fix the proxy/load-balancer rewrite rules (http->https should use 307/308 for API endpoints)."],"exampleFix":"// before (~/.config/hub)\nghe.example.com:\n- protocol: http\n// after\nghe.example.com:\n- protocol: https\n  user: octocat\n  oauth_token: xxxx","handlingStrategy":"validation","validationCode":"// Pre-flight: follow the target with a HEAD request and inspect the chain:\nclient := &http.Client{CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }}\nresp, _ := client.PostForm(baseURL+\"/api/v3/foo\", url.Values{})\nif resp.StatusCode == 301 || resp.StatusCode == 302 {\n    log.Fatalf(\"server redirects with %d; configure the final URL directly: %s\", resp.StatusCode, resp.Header.Get(\"Location\"))\n}","typeGuard":null,"tryCatchPattern":"if err := doAPIPost(); err != nil {\n    if strings.Contains(err.Error(), \"refusing to follow HTTP\") {\n        return fmt.Errorf(\"server/proxy misconfiguration: use 307/308 for method-preserving redirects or point the client at the final URL: %w\", err)\n    }\n    return err\n}","preventionTips":["Configure protocol: https (and the canonical host) in ~/.config/hub so no redirect occurs","Have site admins use 307/308 for http->https rewrites of API endpoints","Point proxy health/rewrite rules away from 301/302 for POST-bearing API routes","Resolve redirects once at setup time and store the final base URL"],"tags":["http","redirect","network","github-enterprise"],"backgroundTag":"http-redirect-method-change","analyzedSha":"5c547ed804368763064e51f3990851e267e88edd","analyzedAt":"2026-09-01T03:34:15.525Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}