mislav/hub · error

refusing to follow HTTP %d redirect for a %s request Have yo

Error message

refusing to follow HTTP %d redirect for a %s request
Have your site admin use HTTP %d for this kind of redirect

What it means

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.

Source

Thrown at github/http.go:223

	return &http.Client{
		Transport:     tr,
		CheckRedirect: checkRedirect,
	}
}

func checkRedirect(req *http.Request, via []*http.Request) error {
	var recommendedCode int
	switch req.Response.StatusCode {
	case 301:
		recommendedCode = 308
	case 302:
		recommendedCode = 307
	}

	origMethod := via[len(via)-1].Method
	if recommendedCode != 0 && !strings.EqualFold(req.Method, origMethod) {
		return fmt.Errorf(
			"refusing to follow HTTP %d redirect for a %s request\n"+
				"Have your site admin use HTTP %d for this kind of redirect",
			req.Response.StatusCode, origMethod, recommendedCode)
	}

	// inherited from stdlib defaultCheckRedirect
	if len(via) >= 10 {
		return errors.New("stopped after 10 redirects")
	}
	return nil
}

func cloneRequest(req *http.Request) *http.Request {
	dup := new(http.Request)
	*dup = *req
	dup.URL, _ = url.Parse(req.URL.String())
	dup.Header = make(http.Header)
	for k, s := range req.Header {

View on GitHub (pinned to 5c547ed804)

Solutions

  1. Ask the site admin to return 307 (for 302) or 308 (for 301) for method-preserving redirects, as the message instructs.
  2. Change the configured protocol to the redirect target directly: set `protocol: https` (or the canonical host) in ~/.config/hub so no redirect occurs.
  3. Update the API base URL used by the client to the final destination URL.
  4. Fix the proxy/load-balancer rewrite rules (http->https should use 307/308 for API endpoints).

Example fix

// before (~/.config/hub)
ghe.example.com:
- protocol: http
// after
ghe.example.com:
- protocol: https
  user: octocat
  oauth_token: xxxx
Defensive patterns

Strategy: validation

Validate before calling

// Pre-flight: follow the target with a HEAD request and inspect the chain:
client := &http.Client{CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }}
resp, _ := client.PostForm(baseURL+"/api/v3/foo", url.Values{})
if resp.StatusCode == 301 || resp.StatusCode == 302 {
    log.Fatalf("server redirects with %d; configure the final URL directly: %s", resp.StatusCode, resp.Header.Get("Location"))
}

Try / catch

if err := doAPIPost(); err != nil {
    if strings.Contains(err.Error(), "refusing to follow HTTP") {
        return fmt.Errorf("server/proxy misconfiguration: use 307/308 for method-preserving redirects or point the client at the final URL: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of mislav/hub@5c547ed804 (2026-09-01). Data as JSON: /api/errors/b7973f301d03958f. Report an issue: GitHub.