{"record":{"id":"c83e71eb8e73c593","repo":"projectdiscovery/nuclei","slug":"http-d-when-downloading-openapi-spec","errorCode":null,"errorMessage":"HTTP %d when downloading OpenAPI spec","messagePattern":"HTTP (.+?) when downloading OpenAPI spec","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/input/formats/openapi/downloader.go","lineNumber":55,"sourceCode":"\tvar client *http.Client\n\tif httpClient != nil {\n\t\tclient = httpClient.HTTPClient\n\t} else {\n\t\t// Fallback to simple client if no httpClient provided\n\t\tclient = &http.Client{Timeout: 30 * time.Second}\n\t}\n\n\tresp, err := client.Get(urlStr)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to download OpenAPI spec\")\n\t}\n\n\tdefer func() {\n\t\t_ = resp.Body.Close()\n\t}()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"HTTP %d when downloading OpenAPI spec\", resp.StatusCode)\n\t}\n\n\tbodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, maxSpecSizeBytes))\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to read response body\")\n\t}\n\n\t// Validate it's a valid JSON and has OpenAPI structure\n\tvar spec map[string]interface{}\n\tif err := json.Unmarshal(bodyBytes, &spec); err != nil {\n\t\treturn \"\", fmt.Errorf(\"downloaded content is not valid JSON: %w\", err)\n\t}\n\n\t// Check if it's an OpenAPI 3.0 spec\n\tif openapi, exists := spec[\"openapi\"]; exists {\n\t\tif openapiStr, ok := openapi.(string); ok && strings.HasPrefix(openapiStr, \"3.\") {\n\t\t\t// Valid OpenAPI 3.0 spec\n\t\t} else {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/input/formats/openapi/downloader.go#L37-L73","documentation":"OpenAPIDownloader.Download fetched the URL successfully but got a non-200 HTTP status. The response status is embedded in the message (e.g. HTTP 401, 404, 503). The request goes through the configured retryablehttp client (or a 30s-timeout fallback), so this is purely a server-side response code failure after transport succeeded.","triggerScenarios":"401/403 from an auth-gated spec endpoint; 404 from a wrong or moved spec path; 302→login page when a redirect target does not return 200; 429/5xx from rate limiting or transient outages; corporate proxy returning 407.","commonSituations":"Internal API portals that require session cookies or bearer tokens (the downloader sends none); stale spec URLs after API restructuring; CI environments behind proxies that intercept the request; rate-limited public APIs.","solutions":["Verify the URL with `curl -i <url>` and confirm it returns 200 from the same network/proxy context","If the spec needs auth headers, download it yourself (curl -H 'Authorization: ...' -o spec.json) and run `nuclei -l spec.json`","Check proxy environment variables (HTTP_PROXY/HTTPS_PROXY) and bypass rules in nuclei config","For transient 5xx/429, retry after a delay or from a different network"],"exampleFix":"# before (spec endpoint requires auth -> HTTP 401)\nnuclei -im openapi -u https://internal/api/openapi.json\n\n# after\ncurl -sH \"Authorization: Bearer $TOKEN\" https://internal/api/openapi.json -o spec.json\nnuclei -l spec.json","handlingStrategy":"retry","validationCode":"resp, err := http.Head(url) // or retryablehttp\nif err != nil {\n    return err\n}\nif resp.StatusCode != http.StatusOK {\n    return fmt.Errorf(\"preflight: spec URL returned %d; fix URL/auth before running nuclei\", resp.StatusCode)\n}","typeGuard":null,"tryCatchPattern":"var path string\nvar err error\nfor attempt := 0; attempt < 3; attempt++ {\n    path, err = downloader.Download(url, tmp, client)\n    if err == nil {\n        break\n    }\n    if strings.Contains(err.Error(), \"HTTP 5\") || strings.Contains(err.Error(), \"HTTP 429\") {\n        time.Sleep(time.Duration(attempt+1) * 2 * time.Second)\n        continue\n    }\n    return err // 4xx: fail fast, retrying will not help\n}","preventionTips":["curl -i the spec URL from the same network before starting a scan","Use locally downloaded specs for auth-gated endpoints (nuclei -l spec.json)","Keep proxy exclusions current for internal spec hosts"],"tags":["openapi","http","network","status-code","download"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}