{"record":{"id":"29b0ee8e4343f54c","repo":"projectdiscovery/nuclei","slug":"http-d-when-downloading-swagger-spec","errorCode":null,"errorMessage":"HTTP %d when downloading Swagger spec","messagePattern":"HTTP (.+?) when downloading Swagger spec","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/input/formats/swagger/downloader.go","lineNumber":64,"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 Swagger 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 Swagger 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// Determine format and parse\n\tvar spec map[string]interface{}\n\tvar isYAML bool\n\n\t// Try JSON first\n\tif err := json.Unmarshal(bodyBytes, &spec); err != nil {\n\t\t// Then try YAML\n\t\tif err := yaml.Unmarshal(bodyBytes, &spec); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"downloaded content is neither valid JSON nor YAML: %w\", err)\n\t\t}\n\t\tisYAML = true","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/input/formats/swagger/downloader.go#L46-L82","documentation":"SwaggerDownloader.Download fetched the spec URL but received a non-200 status; the status code is embedded in the message. Transport succeeded (otherwise you would see 'failed to download Swagger spec'), so this reflects the server's answer: auth failures, wrong paths, rate limits, or server errors.","triggerScenarios":"401/403 on auth-protected spec endpoints; 404 for moved specs; 429 or 5xx under load; 407 from corporate proxies; CDN blocks returning 403 for non-browser user agents.","commonSituations":"Internal portals requiring cookies/tokens; stale URLs after API version migrations; CI networks behind intercepting proxies; anti-bot protection on public docs.","solutions":["Reproduce with `curl -i <url>` from the same machine/proxy and confirm 200","If auth is required, download with the needed headers and use `nuclei -l spec.json`","Fix the URL if 404 (check the docs UI for the current spec path)","Retry later for 429/5xx or use a local copy"],"exampleFix":"# before (auth-gated -> HTTP 401)\nnuclei -im swagger -u https://host/v2/swagger.json\n\n# after\ncurl -sH \"Authorization: Bearer $TOKEN\" https://host/v2/swagger.json -o swagger.json\nnuclei -l swagger.json -im swagger","handlingStrategy":"retry","validationCode":"resp, err := http.Head(url)\nif err != nil {\n    return err\n}\nif resp.StatusCode != http.StatusOK {\n    return fmt.Errorf(\"spec URL answered %d; fix URL/auth or download manually\", resp.StatusCode)\n}","typeGuard":null,"tryCatchPattern":"for attempt := 0; attempt < 3; attempt++ {\n    path, err = downloader.Download(url, tmp, client)\n    if err == nil || !strings.Contains(err.Error(), \"HTTP 5\") && !strings.Contains(err.Error(), \"HTTP 429\") {\n        break\n    }\n    time.Sleep(time.Duration(attempt+1) * 2 * time.Second)\n}","preventionTips":["Preflight spec URLs with curl -i from the scan host","Keep local copies of auth-gated specs","Alert on 404s so stale spec URLs get fixed before scan time"],"tags":["swagger","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"}