{"record":{"id":"ac67f2cdf324f2be","repo":"projectdiscovery/nuclei","slug":"failed-to-read-header-line-s","errorCode":null,"errorMessage":"failed to read header line: %s","messagePattern":"failed to read header line: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/input/types/http.go","lineNumber":267,"sourceCode":"\t\t// remainder of the request target unchanged.\n\t\tif scheme, rest, ok := strings.Cut(target, urlutil.SchemeSeparator); ok {\n\t\t\ttarget = strings.ToLower(scheme) + urlutil.SchemeSeparator + rest\n\t\t}\n\t\turlx, err = urlutil.ParseAbsoluteURL(target, true)\n\t} else {\n\t\turlx, err = urlutil.ParseRawRelativePath(target, true)\n\t}\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to parse url: %s\", err)\n\t}\n\trr.URL = *urlx\n\n\t// parse headers\n\trr.Request.Headers = mapsutil.NewOrderedMap[string, string]()\n\tfor {\n\t\tline, err := protoReader.ReadLine()\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to read header line: %s\", err)\n\t\t}\n\t\tif line == \"\" {\n\t\t\t// end of headers next is body\n\t\t\tbreak\n\t\t}\n\t\tkey, value, found := strings.Cut(line, \":\")\n\t\tif !found || key == \"\" {\n\t\t\treturn nil, fmt.Errorf(\"invalid header line: %s\", line)\n\t\t}\n\t\tvalue = strings.TrimSpace(value)\n\t\t// Host carries the authority rather than request metadata, and callers\n\t\t// read it off the URL: retryablehttp derives the wire Host from there,\n\t\t// and keeping it in the header map would expose it to header fuzzing as\n\t\t// if it were an ordinary header.\n\t\tif strings.EqualFold(key, \"Host\") {\n\t\t\t// an absolute request target takes precedence over the Host header\n\t\t\tif rr.URL.Host == \"\" {\n\t\t\t\trr.URL.Host = value","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/input/types/http.go#L249-L285","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nraw: |\n  GET / HTTP/1.1\n  Host: example.com\n\n# after\nraw: |\n  GET / HTTP/1.1\n  Host: example.com\n\n  ","handlingStrategy":"validation","validationCode":"normalized := strings.ReplaceAll(raw, \"\\r\\n\", \"\\n\")\nhead := strings.SplitN(normalized, \"\\n\\n\", 2)\nif len(head) != 2 {\n    return fmt.Errorf(\"raw request missing blank line after headers\")\n}","typeGuard":null,"tryCatchPattern":"On this error, append the missing blank line terminator to the raw request and re-parse once; if it still fails, drop the entry.","preventionTips":["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)"],"tags":["input","raw-http","parsing","template"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}