projectdiscovery/nuclei · error
failed to parse url: %s
Error message
failed to parse url: %s
What it means
ParseRawRequest could not turn the request target (second token of the method line) into a URL. Absolute-form targets (http://.../https://...) go through urlutil.ParseAbsoluteURL with strict=true; origin-form targets go through urlutil.ParseRawRelativePath, which expects a path starting with '/' and valid path/query syntax.
Source
Thrown at pkg/input/types/http.go:258
method := parts[0]
rr.Request.Method = method
// the request target is normally an origin-form path, but proxy captures and
// .http files use the absolute form, which already carries the authority
var urlx *urlutil.URL
target := parts[1]
if stringsutil.HasPrefixAnyI(target, urlutil.HTTP+urlutil.SchemeSeparator, urlutil.HTTPS+urlutil.SchemeSeparator) {
// urlutil.ParseAbsoluteURL only accepts lowercase schemes; preserve the
// 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)
}View on GitHub (pinned to 265b3a3dec)
Solutions
- Use an origin-form target starting with '/', e.g. '/api/v1/users?id=1', or a full absolute URL
- Percent-encode spaces and unsafe characters in the path/query
- Replace 'OPTIONS *' with 'OPTIONS / HTTP/1.1' (asterisk-form is unsupported)
- Wrap IPv6 hosts in brackets: http://[::1]:8080/
Example fix
# before raw: | GET api/users?id=1 HTTP/1.1 # after raw: | GET /api/users?id=1 HTTP/1.1
Defensive patterns
Strategy: validation
Validate before calling
target := parts[1]
if strings.HasPrefix(strings.ToLower(target), "http://") || strings.HasPrefix(strings.ToLower(target), "https://") {
if _, err := url.Parse(target); err != nil { return err }
} else if !strings.HasPrefix(target, "/") {
return fmt.Errorf("origin-form target must start with '/': %q", target)
} Try / catch
Catch the parse failure, normalize the target (add leading '/', percent-encode spaces), and re-parse once before giving up on the entry.
Prevention
- Keep the leading '/' on paths; percent-encode unsafe characters
- Avoid asterisk-form targets — the parser does not support them
- Bracket IPv6 literals in absolute targets
When it happens
Trigger: Relative target without a leading slash ('api/foo'), containing spaces or control chars, or '*'; absolute target with bad authority (e.g. 'http:///path', 'https://host:port:notaport/'). Mixed-case schemes like HTTP:// are handled by lowercasing, so that is not the cause.
Common situations: Pasting paths without the leading slash; unencoded spaces in query strings from manual edits; asterisk-form OPTIONS requests ('OPTIONS * HTTP/1.1') which this parser does not support; IPv6 literals missing brackets.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to read method line: %s
- invalid method line: %s
- failed to read header line: %s
- invalid header line: %s
- template threads must be at least 1
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/d6c8c02e0121042a.
Report an issue: GitHub.