projectdiscovery/nuclei · error

HTTP %d when downloading Swagger spec

Error message

HTTP %d when downloading Swagger spec

What it means

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.

Source

Thrown at pkg/input/formats/swagger/downloader.go:64

	var client *http.Client
	if httpClient != nil {
		client = httpClient.HTTPClient
	} else {
		// Fallback to simple client if no httpClient provided
		client = &http.Client{Timeout: 30 * time.Second}
	}

	resp, err := client.Get(urlStr)
	if err != nil {
		return "", errors.Wrap(err, "failed to download Swagger spec")
	}

	defer func() {
		_ = resp.Body.Close()
	}()

	if resp.StatusCode != http.StatusOK {
		return "", fmt.Errorf("HTTP %d when downloading Swagger spec", resp.StatusCode)
	}

	bodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, maxSpecSizeBytes))
	if err != nil {
		return "", errors.Wrap(err, "failed to read response body")
	}

	// Determine format and parse
	var spec map[string]interface{}
	var isYAML bool

	// Try JSON first
	if err := json.Unmarshal(bodyBytes, &spec); err != nil {
		// Then try YAML
		if err := yaml.Unmarshal(bodyBytes, &spec); err != nil {
			return "", fmt.Errorf("downloaded content is neither valid JSON nor YAML: %w", err)
		}
		isYAML = true

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Reproduce with `curl -i <url>` from the same machine/proxy and confirm 200
  2. If auth is required, download with the needed headers and use `nuclei -l spec.json`
  3. Fix the URL if 404 (check the docs UI for the current spec path)
  4. Retry later for 429/5xx or use a local copy

Example fix

# before (auth-gated -> HTTP 401)
nuclei -im swagger -u https://host/v2/swagger.json

# after
curl -sH "Authorization: Bearer $TOKEN" https://host/v2/swagger.json -o swagger.json
nuclei -l swagger.json -im swagger
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Head(url)
if err != nil {
    return err
}
if resp.StatusCode != http.StatusOK {
    return fmt.Errorf("spec URL answered %d; fix URL/auth or download manually", resp.StatusCode)
}

Try / catch

for attempt := 0; attempt < 3; attempt++ {
    path, err = downloader.Download(url, tmp, client)
    if err == nil || !strings.Contains(err.Error(), "HTTP 5") && !strings.Contains(err.Error(), "HTTP 429") {
        break
    }
    time.Sleep(time.Duration(attempt+1) * 2 * time.Second)
}

Prevention

When it happens

Trigger: 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.

Common situations: Internal portals requiring cookies/tokens; stale URLs after API version migrations; CI networks behind intercepting proxies; anti-bot protection on public docs.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/29b0ee8e4343f54c. Report an issue: GitHub.