valyala/fasthttp · error
fasthttp: unexpected char at the end of status code
Error message
fasthttp: unexpected char at the end of status code
What it means
While parsing a response status line, fasthttp reads the 3-digit status code and expects it to be followed by a space, CR/LF, or end of line. If an unexpected character appears where the status code should end, ErrUnexpectedStatusCodeChar is returned. It indicates the peer sent a syntactically invalid status line.
Source
Thrown at header.go:473
// The following trailers are forbidden:
// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),
// 2. routing (e.g., Host),
// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),
// 4. authentication (e.g., see [RFC7235] and [RFC6265]),
// 5. response control data (e.g., see Section 7.1 of [RFC7231]),
// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)
//
// Return ErrBadTrailer if contain any forbidden trailers.
func (h *header) AddTrailer(trailer string) error {
return h.AddTrailerBytes(s2b(trailer))
}
var (
ErrBadTrailer = errors.New("fasthttp: contain forbidden trailer")
ErrReadingResponseHeaders = errors.New("fasthttp: error when reading response headers")
ErrReadingResponseTrailer = errors.New("fasthttp: error when reading response trailer")
ErrResponseFirstLineMissingSpace = errors.New("fasthttp: cannot find whitespace in the first line of response")
ErrUnexpectedStatusCodeChar = errors.New("fasthttp: unexpected char at the end of status code")
ErrMissingRequestMethod = errors.New("fasthttp: cannot find http request method")
ErrUnsupportedRequestMethod = errors.New("fasthttp: unsupported http request method")
ErrExtraWhitespaceInRequestLine = errors.New("fasthttp: extra whitespace in request line")
ErrEmptyRequestURI = errors.New("fasthttp: requesturi cannot be empty")
ErrDuplicateContentLength = errors.New("fasthttp: duplicate content-length header")
ErrUnsupportedTransferEncoding = errors.New("fasthttp: unsupported transfer-encoding")
ErrNonNumericChars = errors.New("fasthttp: non-numeric chars found")
ErrNeedMore = errors.New("fasthttp: need more data: cannot find trailing lf")
ErrSmallReadBuffer = errors.New("fasthttp: small read buffer. increase readbuffersize")
)
// AddTrailerBytes add Trailer header value for chunked response
// to indicate which headers will be sent after the body.
//
// Use Set to set the trailer header later.
//
// Trailers are only supported with chunked transfer.
// Trailers allow the sender to include additional headers at the end of chunked messages.View on GitHub (pinned to c96f600972)
Solutions
- Log the raw first line (wrap the conn or use curl -v against the same URL) to see what the peer actually returns.
- Fix the upstream server/proxy to emit RFC-compliant status lines like 'HTTP/1.1 200 OK'.
- Ensure the https:// scheme and TLSClientConfig are set for TLS servers so ciphertext is not parsed as plain HTTP.
- Retry against a healthy endpoint; fasthttp closes the connection after this parse error so the pooled conn is discarded.
Example fix
// before
req.SetRequestURI("http://svc.internal:8443/x") // TLS server, plain HTTP request
// after
req.SetRequestURI("https://svc.internal:8443/x")
client.TLSConfig = &tls.Config{ InsecureSkipVerify: true } // trust setup as needed Defensive patterns
Strategy: type-guard
Validate before calling
// Probe the raw status line once at startup:
// curl -sv URL | head -1 must match '^HTTP/1\.[01] [0-9]{3} '
Type guard
func isBadStatusLine(err error) bool {
return err == fasthttp.ErrUnexpectedStatusCodeChar
} Try / catch
err := client.Do(req, resp)
if err == fasthttp.ErrUnexpectedStatusCodeChar {
client.CloseIdleConnections() // discard possibly-corrupted pooled conns
return retryable(fmt.Errorf("malformed status line: %w", err))
} Prevention
- Use TLS (https scheme) with TLS servers so ciphertext is never parsed as HTTP.
- Pin and test upstream server versions in CI — nonconformant proxies emit bad status lines.
- Log first bytes of failed responses via a wrapped dialer for diagnosis.
- Treat bursts of this error as a compromised/misbehaving middlebox signal.
When it happens
Trigger: Response.Read / Client.Do / HostClient.Do on a response whose first line is like 'HTTP/1.1 20x OK' or 'HTTP/1.1 1234abc' — any non-digit/non-separator char after the status digits (see fasthttputil/ParseUint usage in parseFirstLine).
Common situations: Talking to a misbehaving or nonconformant server/proxy, an adversarial or fuzzed peer, or a port returning proprietary protocol data instead of HTTP. Also common when TLS is missing so raw handshake bytes are parsed as HTTP.
Related errors
- fasthttp: cannot find whitespace in the first line of respon
- fasthttp: error when reading response headers
- error when reading request headers: %w
- cannot find whitespace in the first line of response %q
- invalid response status code %q: response %q
AI-assisted analysis of valyala/fasthttp@c96f600972 (2026-08-31).
Data as JSON: /api/errors/c43d9d2b259a26a8.
Report an issue: GitHub.