projectdiscovery/nuclei · error
failed to read header line: %s
Error message
failed to read header line: %s
What it means
While looping over header lines, textproto ReadLine returned an error before the blank line that terminates the header block. In practice: EOF, meaning the raw request was truncated and never contains the empty line separating headers from body.
Source
Thrown at pkg/input/types/http.go:267
// remainder of the request target unchanged.
if scheme, rest, ok := strings.Cut(target, urlutil.SchemeSeparator); ok {
target = strings.ToLower(scheme) + urlutil.SchemeSeparator + rest
}
urlx, err = urlutil.ParseAbsoluteURL(target, true)
} else {
urlx, err = urlutil.ParseRawRelativePath(target, true)
}
if err != nil {
return nil, fmt.Errorf("failed to parse url: %s", err)
}
rr.URL = *urlx
// parse headers
rr.Request.Headers = mapsutil.NewOrderedMap[string, string]()
for {
line, err := protoReader.ReadLine()
if err != nil {
return nil, fmt.Errorf("failed to read header line: %s", err)
}
if line == "" {
// end of headers next is body
break
}
key, value, found := strings.Cut(line, ":")
if !found || key == "" {
return nil, fmt.Errorf("invalid header line: %s", line)
}
value = strings.TrimSpace(value)
// Host carries the authority rather than request metadata, and callers
// read it off the URL: retryablehttp derives the wire Host from there,
// and keeping it in the header map would expose it to header fuzzing as
// if it were an ordinary header.
if strings.EqualFold(key, "Host") {
// an absolute request target takes precedence over the Host header
if rr.URL.Host == "" {
rr.URL.Host = valueView on GitHub (pinned to 265b3a3dec)
Solutions
- Terminate the header block with one empty line before the body (CRLF CRLF in wire format)
- If there is no body, still end the raw request with the blank line after headers
- Re-export the request from Burp 'Copy as raw' including the empty line
Example fix
# before raw: | GET / HTTP/1.1 Host: example.com # after raw: | GET / HTTP/1.1 Host: example.com
Defensive patterns
Strategy: validation
Validate before calling
normalized := strings.ReplaceAll(raw, "\r\n", "\n")
head := strings.SplitN(normalized, "\n\n", 2)
if len(head) != 2 {
return fmt.Errorf("raw request missing blank line after headers")
} Try / catch
On this error, append the missing blank line terminator to the raw request and re-parse once; if it still fails, drop the entry.
Prevention
- Always terminate the header block with a truly empty line
- Export raw requests from Burp 'Copy as raw' rather than retyping
- In YAML templates keep the blank line inside the block scalar (indent it like the rest)
When it happens
Trigger: Raw request whose header section is not terminated by an empty line: input ends right after the last header, or the blank line was lost in copy-paste/YAML indentation.
Common situations: Templates where the raw block scalar omits the trailing blank line; CRLF confusion — note the parser breaks on a completely empty line, so ensure the separator line is truly empty (no stray spaces); truncated files.
Related errors
- failed to read method line: %s
- invalid method line: %s
- failed to parse url: %s
- invalid header line: %s
- response read size must be non-negative
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/ac67f2cdf324f2be.
Report an issue: GitHub.