labstack/echo · error

ErrInvalidRedirectCode

ErrInvalidRedirectCode

Error message

invalid redirect status code

What it means

ErrInvalidRedirectCode is returned by Context.Redirect when the status code is outside the HTTP 3xx redirect range (code < 300 || code > 308). Only 300-308 are valid redirect status codes per HTTP spec; passing anything else (200, 404, 201, etc.) is a programmer error.

Source

Thrown at httperror.go:32

	ErrBadRequest                  = &httpError{http.StatusBadRequest}            // 400
	ErrUnauthorized                = &httpError{http.StatusUnauthorized}          // 401
	ErrForbidden                   = &httpError{http.StatusForbidden}             // 403
	ErrNotFound                    = &httpError{http.StatusNotFound}              // 404
	ErrMethodNotAllowed            = &httpError{http.StatusMethodNotAllowed}      // 405
	ErrRequestTimeout              = &httpError{http.StatusRequestTimeout}        // 408
	ErrStatusRequestEntityTooLarge = &httpError{http.StatusRequestEntityTooLarge} // 413
	ErrUnsupportedMediaType        = &httpError{http.StatusUnsupportedMediaType}  // 415
	ErrTooManyRequests             = &httpError{http.StatusTooManyRequests}       // 429
	ErrInternalServerError         = &httpError{http.StatusInternalServerError}   // 500
	ErrBadGateway                  = &httpError{http.StatusBadGateway}            // 502
	ErrServiceUnavailable          = &httpError{http.StatusServiceUnavailable}    // 503
)

// The following errors fall into 500 (InternalServerError) category
var (
	ErrValidatorNotRegistered = errors.New("validator not registered")
	ErrRendererNotRegistered  = errors.New("renderer not registered")
	ErrInvalidRedirectCode    = errors.New("invalid redirect status code")
	ErrCookieNotFound         = errors.New("cookie not found")
	ErrInvalidCertOrKeyType   = errors.New("invalid cert or key type, must be string or []byte")
	ErrInvalidListenerNetwork = errors.New("invalid listener network")
)

// HTTPStatusCoder is an interface that errors can implement to produce status code for HTTP response
type HTTPStatusCoder interface {
	StatusCode() int
}

// StatusCode returns status code from err if it implements HTTPStatusCoder interface.
// If err does not implement the interface, it returns 0.
func StatusCode(err error) int {
	var sc HTTPStatusCoder
	if errors.As(err, &sc) {
		return sc.StatusCode()
	}
	return 0

View on GitHub (pinned to 05489dc173)

Solutions

  1. Use a valid redirect code: 301 (MovedPermanently), 302 (Found), 303 (SeeOther), 307 (TemporaryRedirect), or 308 (PermanentRedirect)
  2. For non-redirect responses use c.String/c.JSON/c.HTML instead of c.Redirect
  3. Define named constants for your redirect codes to avoid magic numbers

Example fix

// before
c.Redirect(http.StatusCreated, "/new") // 201 — error

// after
c.Redirect(http.StatusFound, "/new") // 302 — ok
Defensive patterns

Strategy: validation

Validate before calling

// Validate redirect code before calling Redirect
func validRedirectCode(code int) bool {
    return code >= 300 && code <= 308
}
if !validRedirectCode(code) {
    return fmt.Errorf("invalid redirect code: %d", code)
}
c.Redirect(code, url)

Try / catch

if err := c.Redirect(code, url); err != nil {
    if errors.Is(err, echo.ErrInvalidRedirectCode) {
        return echo.NewHTTPError(http.StatusInternalServerError, "misconfigured redirect")
    }
    return err
}

Prevention

When it happens

Trigger: Calling c.Redirect(http.StatusCreated, url) or c.Redirect(200, url) or c.Redirect(404, url). Any status code outside [300,308] triggers it.

Common situations: Using http.StatusCreated (201) or http.StatusOK (200) by mistake instead of http.StatusMovedPermanently (301) or http.StatusFound (302). Copy-pasting a status constant from elsewhere.

Related errors


AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04). Data as JSON: /data/errors/c1318dff867211e7.json. Report an issue: GitHub.