{"record":{"id":"206b655f1a486a1c","repo":"valyala/fasthttp","slug":"fasthttp-need-more-data-cannot-find-trailing-lf","errorCode":null,"errorMessage":"fasthttp: need more data: cannot find trailing lf","messagePattern":"fasthttp: need more data: cannot find trailing lf","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"header.go","lineNumber":481,"sourceCode":"// Return ErrBadTrailer if contain any forbidden trailers.\nfunc (h *header) AddTrailer(trailer string) error {\n\treturn h.AddTrailerBytes(s2b(trailer))\n}\n\nvar (\n\tErrBadTrailer                    = errors.New(\"fasthttp: contain forbidden trailer\")\n\tErrReadingResponseHeaders        = errors.New(\"fasthttp: error when reading response headers\")\n\tErrReadingResponseTrailer        = errors.New(\"fasthttp: error when reading response trailer\")\n\tErrResponseFirstLineMissingSpace = errors.New(\"fasthttp: cannot find whitespace in the first line of response\")\n\tErrUnexpectedStatusCodeChar      = errors.New(\"fasthttp: unexpected char at the end of status code\")\n\tErrMissingRequestMethod          = errors.New(\"fasthttp: cannot find http request method\")\n\tErrUnsupportedRequestMethod      = errors.New(\"fasthttp: unsupported http request method\")\n\tErrExtraWhitespaceInRequestLine  = errors.New(\"fasthttp: extra whitespace in request line\")\n\tErrEmptyRequestURI               = errors.New(\"fasthttp: requesturi cannot be empty\")\n\tErrDuplicateContentLength        = errors.New(\"fasthttp: duplicate content-length header\")\n\tErrUnsupportedTransferEncoding   = errors.New(\"fasthttp: unsupported transfer-encoding\")\n\tErrNonNumericChars               = errors.New(\"fasthttp: non-numeric chars found\")\n\tErrNeedMore                      = errors.New(\"fasthttp: need more data: cannot find trailing lf\")\n\tErrSmallReadBuffer               = errors.New(\"fasthttp: small read buffer. increase readbuffersize\")\n)\n\n// AddTrailerBytes add Trailer header value for chunked response\n// to indicate which headers will be sent after the body.\n//\n// Use Set to set the trailer header later.\n//\n// Trailers are only supported with chunked transfer.\n// Trailers allow the sender to include additional headers at the end of chunked messages.\n//\n// The following trailers are forbidden:\n// 1. necessary for message framing (e.g., Transfer-Encoding and Content-Length),\n// 2. routing (e.g., Host),\n// 3. request modifiers (e.g., controls and conditionals in Section 5 of [RFC7231]),\n// 4. authentication (e.g., see [RFC7235] and [RFC6265]),\n// 5. response control data (e.g., see Section 7.1 of [RFC7231]),\n// 6. determining how to process the payload (e.g., Content-Encoding, Content-Type, Content-Range, and Trailer)","sourceCodeStart":463,"sourceCodeEnd":499,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/header.go#L463-L499","documentation":"ErrNeedMore is fasthttp's internal flow-control sentinel: header/body parsers return it when the buffer holds an incomplete chunk of data and more bytes must be read (no trailing LF of the header section yet). It is primarily internal — IO read loops (header.go Read, headerscanner.next) treat it as 'read more' — but it is exported and can escape to user code or tests when a parse is attempted on a truncated buffer.","triggerScenarios":"Attempting Request.Read/Response.Read (or Header.Read) against a byte stream that ends mid-headers (no terminating \\r\\n\\r\\n); manually invoking the header scanner with a partial buffer; a peer closing the connection before the full header block arrives (see the `next` path in headerscanner.go and Read in header.go:2177).","commonSituations":"Reading from a fasthttputil.PipeConn or in-memory stream before the writer finished; truncated responses from unstable upstreams; hand-rolled framing code that splits reads and forgets the final CRLF; network timeouts cutting a response in half.","solutions":["If you call read APIs directly, loop until a non-ErrNeedMore error or EOF, appending newly read bytes into the same buffer.","Ensure the peer actually sends the terminating CRLF blank line; fix the client/server that truncates the header block.","Check for network timeouts/close racing the read — increase ReadTimeout or fix premature conn.Close().","Do not treat ErrNeedMore as a user-facing failure in your own error mapping; translate it into retry/continue logic."],"exampleFix":"// before\nerr := h.Read(r)\nif err != nil { return err } // ErrNeedMore leaks to caller on partial data\n// after\nfor {\n    if err := h.Read(r); err == fasthttp.ErrNeedMore {\n        continue // read more data into buffer\n    } else if err != nil {\n        return err\n    }\n    break\n}","handlingStrategy":"try-catch","validationCode":"// Before parsing a buffered message, require the header terminator:\nif !bytes.Contains(buf, []byte(\"\\r\\n\\r\\n\")) && !bytes.Contains(buf, []byte(\"\\n\\n\")) {\n    return fasthttp.ErrNeedMore // keep buffering, do not treat as failure\n}","typeGuard":"func needsMoreData(err error) bool {\n    return err == fasthttp.ErrNeedMore\n}","tryCatchPattern":"for {\n    err := h.Read(r)\n    if err == fasthttp.ErrNeedMore {\n        continue // buffer and read more from the connection\n    }\n    if err != nil {\n        return err\n    }\n    break\n}","preventionTips":["Never map ErrNeedMore to a user-facing error — it means 'read more', not 'failed'.","Ensure senders always terminate headers with the blank CRLF line.","Check ReadTimeout/conn.Close races that truncate responses mid-headers.","When reading from in-memory pipes, wait for the writer to flush the full header block before parsing."],"tags":["http","fasthttp","streaming","parsing"],"backgroundTag":"incomplete-http-message","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}