{"record":{"id":"be2352de7896fa81","repo":"projectdiscovery/nuclei","slug":"http-url-must-include-scheme-and-host","errorCode":null,"errorMessage":"http: url must include scheme and host","messagePattern":"http: url must include scheme and host","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/js/libs/http/http.go","lineNumber":262,"sourceCode":"\t\tMaxBodyBytes:    defaultMaxBodyBytes,\n\t\theaders:         make(http.Header),\n\t}\n}\n\nfunc (c *Client) do(ctx context.Context, method, rawURL, body string) (*Response, error) {\n\tc.init()\n\n\texecutionID := executionIDFrom(ctx, c)\n\tif executionID == \"\" {\n\t\treturn nil, fmt.Errorf(\"http: executionId not set\")\n\t}\n\n\tparsed, err := url.Parse(rawURL)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"http: invalid url: %w\", err)\n\t}\n\tif parsed.Scheme == \"\" || parsed.Host == \"\" {\n\t\treturn nil, fmt.Errorf(\"http: url must include scheme and host\")\n\t}\n\n\thost := parsed.Hostname()\n\tif !protocolstate.IsHostAllowed(executionID, host) {\n\t\treturn nil, protocolstate.ErrHostDenied.Msgf(host)\n\t}\n\n\tdialers := protocolstate.GetDialersWithId(executionID)\n\tif dialers == nil {\n\t\treturn nil, fmt.Errorf(\"dialers not initialized for %s\", executionID)\n\t}\n\n\ttlsConfig := &tls.Config{\n\t\tInsecureSkipVerify: true,\n\t\tMinVersion:         tls.VersionTLS10,\n\t\tRenegotiation:      tls.RenegotiateOnceAsClient,\n\t}\n\tif host != \"\" {","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/js/libs/http/http.go#L244-L280","documentation":"The URL parsed but lacks a scheme or a host: nuclei/http demands absolute URLs like 'https://example.com/path' because host policy needs a hostname to evaluate. Bare hosts ('example.com'), scheme-less paths ('/api'), protocol-relative URLs ('//example.com'), and empty strings all fail here.","triggerScenarios":"client.Get('example.com'); client.Get('/api/v1'); passing only the output of an extractor that captured a path or a Host-header value; scheme omitted because curl-style syntax felt natural; empty string.","commonSituations":"Template authors used to tools where the scheme is optional; concatenating a Host header value without a protocol; building URLs from parts where the scheme variable is unset.","solutions":["Always include scheme and host: client.Get('https://' + host + path)","Default the scheme when missing: if (!/^https?:\\/\\//.test(u)) u = 'https://' + u","Skip the request entirely when an extracted URL is empty or path-only"],"exampleFix":"// before\nconst resp = client.Get(host); // 'example.com' -> no scheme/host\n\n// after: normalize to an absolute URL first\nlet u = String(host || '').trim();\nif (!/^https?:\\/\\//.test(u)) u = 'https://' + u.replace(/^\\/+/, '');\nconst resp = client.Get(u);","handlingStrategy":"validation","validationCode":"function toAbsoluteUrl(u) {\n  const s = String(u || '').trim();\n  if (!s) return null;\n  return /^https?:\\/\\//.test(s) ? s : 'https://' + s.replace(/^\\/+/, '');\n}\nconst url = toAbsoluteUrl(candidate);\nif (url) { const resp = client.Get(url); }","typeGuard":"const hasSchemeAndHost = (u) => /^https?:\\/\\/[^\\s/]+/.test(String(u || '').trim());","tryCatchPattern":"try { const resp = client.Get(u); }\ncatch (e) { if (/must include scheme and host/.test(e.message || '')) { /* prepend https:// and host, then retry */ } }","preventionTips":["Always build URLs as scheme + host + path explicitly","Default missing schemes to https:// before the request","Skip requests whose extracted URL is empty or path-only"],"tags":["http","url","validation","javascript"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}