valyala/fasthttp · error

invalid WriteHeader code %v

Error message

invalid WriteHeader code %v

What it means

fasthttpadaptor's writer adapts net/http handlers to fasthttp. WriteHeader mirrors net/http's constraint that status codes must be 100-999 and panics otherwise, since fasthttp cannot encode such a code on the wire.

Source

Thrown at fasthttpadaptor/adaptor.go:251

	}
}

func releaseWriter(w *writer) {
	_ = w.Close()
	if w.bufPool != nil {
		bufferPool.Put(w.bufPool)
		w.bufPool = nil
	}
}

func (w *writer) Header() http.Header {
	return w.h
}

func (w *writer) WriteHeader(code int) {
	// Allow the same codes as net/http.
	if code < 100 || code > 999 {
		panic(fmt.Sprintf("invalid WriteHeader code %v", code))
	}
	w.statusCode.CompareAndSwap(0, int64(code))
}

func (w *writer) Write(p []byte) (int, error) {
	select {
	case <-w.streamReady:
		return w.pw.Write(p)
	default:
	}

	w.mu.Lock()
	select {
	case <-w.streamReady:
		w.mu.Unlock()
		return w.pw.Write(p)
	default:
	}

View on GitHub (pinned to c96f600972)

Solutions

  1. Only pass valid HTTP status codes 100-999 to WriteHeader
  2. Default to http.StatusOK (200) when no explicit status is needed — omitting WriteHeader entirely also yields 200
  3. Clamp/validate the status value before calling WriteHeader

Example fix

// before
w.WriteHeader(status) // status may be 0
// after
if status < 100 || status > 999 {
    status = http.StatusOK
}
w.WriteHeader(status)
Defensive patterns

Strategy: try-catch

Validate before calling

func safeWriteHeader(w http.ResponseWriter, code int) {
    if code >= 100 && code <= 999 {
        w.WriteHeader(code)
    }
}

Type guard

func isValidStatusCode(code int) bool {
    return code >= 100 && code <= 999
}

Try / catch

func(w http.ResponseWriter, r *http.Request) {
    defer func() {
        if rec := recover(); rec != nil {
            if s, ok := rec.(string); ok && strings.HasPrefix(s, "invalid WriteHeader code") {
                http.Error(w, "internal error", http.StatusInternalServerError)
                return
            }
            panic(rec)
        }
    }()
    nextHandler(w, r)
}

Prevention

When it happens

Trigger: A net/http handler (served via adaptor) calls w.WriteHeader with code < 100 (e.g. 0, 42, 99) or > 999; the panic propagates up through ServeHTTP.

Common situations: Custom status constants initialized to zero and never set (WriteHeader(0)); experiments with out-of-range codes; copied handler code using sentinel values like -1.

Related errors


AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31). Data as JSON: /api/errors/265a2ea3588200ea. Report an issue: GitHub.