projectdiscovery/nuclei · error

HTTP %d when downloading OpenAPI spec

Error message

HTTP %d when downloading OpenAPI spec

What it means

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.

Source

Thrown at pkg/input/formats/openapi/downloader.go:55

	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 OpenAPI spec")
	}

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

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

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

	// Validate it's a valid JSON and has OpenAPI structure
	var spec map[string]interface{}
	if err := json.Unmarshal(bodyBytes, &spec); err != nil {
		return "", fmt.Errorf("downloaded content is not valid JSON: %w", err)
	}

	// Check if it's an OpenAPI 3.0 spec
	if openapi, exists := spec["openapi"]; exists {
		if openapiStr, ok := openapi.(string); ok && strings.HasPrefix(openapiStr, "3.") {
			// Valid OpenAPI 3.0 spec
		} else {

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Verify the URL with `curl -i <url>` and confirm it returns 200 from the same network/proxy context
  2. If the spec needs auth headers, download it yourself (curl -H 'Authorization: ...' -o spec.json) and run `nuclei -l spec.json`
  3. Check proxy environment variables (HTTP_PROXY/HTTPS_PROXY) and bypass rules in nuclei config
  4. For transient 5xx/429, retry after a delay or from a different network

Example fix

# before (spec endpoint requires auth -> HTTP 401)
nuclei -im openapi -u https://internal/api/openapi.json

# after
curl -sH "Authorization: Bearer $TOKEN" https://internal/api/openapi.json -o spec.json
nuclei -l spec.json
Defensive patterns

Strategy: retry

Validate before calling

resp, err := http.Head(url) // or retryablehttp
if err != nil {
    return err
}
if resp.StatusCode != http.StatusOK {
    return fmt.Errorf("preflight: spec URL returned %d; fix URL/auth before running nuclei", resp.StatusCode)
}

Try / catch

var path string
var err error
for attempt := 0; attempt < 3; attempt++ {
    path, err = downloader.Download(url, tmp, client)
    if err == nil {
        break
    }
    if strings.Contains(err.Error(), "HTTP 5") || strings.Contains(err.Error(), "HTTP 429") {
        time.Sleep(time.Duration(attempt+1) * 2 * time.Second)
        continue
    }
    return err // 4xx: fail fast, retrying will not help
}

Prevention

When it happens

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

Common situations: 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.

Related errors


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