gin-gonic/gin · critical

Cannot redirect with status code %d

Error message

Cannot redirect with status code %d

What it means

Redirect.Render (render/redirect.go:22) panics when the status code is outside the HTTP redirect range [300, 308] and is not 201. http.Redirect only accepts 3xx codes (plus 201 Created with a Location), so any other code (200, 404, 500, etc.) is a programmer error and Gin aborts.

Source

Thrown at render/redirect.go:22

package render

import (
	"fmt"
	"net/http"
)

// Redirect contains the http request reference and redirects status code and location.
type Redirect struct {
	Code     int
	Request  *http.Request
	Location string
}

// Render (Redirect) redirects the http request to new location and writes redirect response.
func (r Redirect) Render(w http.ResponseWriter) error {
	if (r.Code < http.StatusMultipleChoices || r.Code > http.StatusPermanentRedirect) && r.Code != http.StatusCreated {
		panic(fmt.Sprintf("Cannot redirect with status code %d", r.Code))
	}
	http.Redirect(w, r.Request, r.Location, r.Code)
	return nil
}

// WriteContentType (Redirect) don't write any ContentType.
func (r Redirect) WriteContentType(http.ResponseWriter) {}

View on GitHub (pinned to 34dac209ff)

Solutions

  1. Use a valid redirect status: 301 (MovedPermanently), 302 (Found), 303 (SeeOther), 307 (TemporaryRedirect), 308 (PermanentRedirect), or 201 (Created) with a Location header.
  2. Use the net/http constants (http.StatusMovedPermanently, http.StatusFound) rather than raw ints.
  3. If you don't want a redirect, use c.JSON / c.String instead of c.Redirect.

Example fix

// before
c.Redirect(http.StatusOK, "/new")
// after
c.Redirect(http.StatusFound, "/new")
Defensive patterns

Strategy: validation

Validate before calling

func isValidRedirectCode(code int) bool {
    return (code >= 300 && code <= 308) || code == http.StatusCreated
}
if !isValidRedirectCode(code) {
    return fmt.Errorf("invalid redirect status %d", code)
}
c.Redirect(code, url)

Prevention

When it happens

Trigger: Calling c.Redirect(http.StatusMovedPermanently, ...) — wait that's valid; calling c.Redirect(http.StatusOK, url) (200 is not a redirect code); c.Redirect(http.StatusFound, ...) is valid but c.Redirect(200, url) panics; passing a custom int that is not 3xx and not 201.

Common situations: Using http.StatusOK or http.StatusBadRequest as the redirect status by mistake; using an enum/constant that resolves to a non-3xx value; copying c.JSON(status, ...) patterns into c.Redirect.

Related errors


AI-assisted analysis of gin-gonic/gin@34dac209ff (2026-08-04). Data as JSON: /data/errors/3fff7a0328aa5af9.json. Report an issue: GitHub.