projectdiscovery/nuclei · error

failed to download %s spec from url %s: %w

Error message

failed to download %s spec from url %s: %w

What it means

Nuclei is trying to turn a URL target into an OpenAPI/Swagger input list. When exactly one -target starting with http(s):// is combined with -im openapi or -im swagger, provider.New() calls the corresponding formats downloader to fetch the spec into a temp file. This error wraps any failure of that Download(): network error, non-200 response, spec parse failure, or temp-file write failure.

Source

Thrown at pkg/input/provider/interface.go:150

				dialers := protocolstate.GetDialersWithId(opts.Options.ExecutionId)
				if dialers != nil {
					httpClient = dialers.DefaultHTTPClient
				}
			}

			switch strings.ToLower(opts.Options.InputFileMode) {
			case "openapi":
				downloader = openapi.NewDownloader()
				tempFile, err = downloader.Download(target, opts.TempDir, httpClient)
			case "swagger":
				downloader = swagger.NewDownloader()
				tempFile, err = downloader.Download(target, opts.TempDir, httpClient)
			default:
				return nil, fmt.Errorf("unsupported input mode: %s", opts.Options.InputFileMode)
			}

			if err != nil {
				return nil, fmt.Errorf("failed to download %s spec from url %s: %w", opts.Options.InputFileMode, target, err)
			}

			opts.Options.TargetsFilePath = tempFile
		}
	}

	return http.NewHttpInputProvider(&http.HttpMultiFormatOptions{
		InputFile: opts.Options.TargetsFilePath,
		InputMode: opts.Options.InputFileMode,
		Options: formats.InputFormatOptions{
			Variables:            generators.MergeMaps(extraVars, opts.Options.Vars.AsMap()),
			SkipFormatValidation: opts.Options.SkipFormatValidation,
			RequiredOnly:         opts.Options.FormatUseRequiredOnly,
			VarsTextTemplating:   opts.Options.VarsTextTemplating,
			VarsFilePaths:        opts.Options.VarsFilePaths,
		},
	})
}

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. Fetch the URL out-of-band (curl -sSL -o spec.json <url>) and confirm it returns 200 with a valid spec body; if auth is required, download manually and pass the file via -l instead of a URL target
  2. Make -im match the spec version: openapi for OpenAPI 3.x documents, swagger for Swagger 2.0
  3. Verify the temp dir (-temp-dir) exists and is writable
  4. For SDK runs, ensure the protocolstate dialer/network policy for that ExecutionId permits the spec host

Example fix

# before
nuclei -t probes -target https://internal/api-spec.json -im openapi

# after
curl -sSL -H "Authorization: Bearer $TOKEN" -o spec.json https://internal/api-spec.json && nuclei -t probes -l spec.json -im openapi
Defensive patterns

Strategy: validation

Validate before calling

resp, err := http.Get(specURL)
if err != nil {
    return fmt.Errorf("preflight failed: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
    return fmt.Errorf("spec URL returned %d — download it manually and pass via -l", resp.StatusCode)
}
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
if !json.Valid(body) {
    return fmt.Errorf("URL did not return JSON — likely an auth/error page")
}

Try / catch

Wrap provider creation (or nuclei run setup) and on this error fall back to feeding the spec as a local file via TargetsFilePath, e.g. download with the needed auth headers yourself, then hand the file to the input provider.

Prevention

When it happens

Trigger: Running with a single http(s) URL target and -im openapi|swagger where downloader.Download(target, opts.TempDir, httpClient) fails: spec URL unreachable, returns 401/403/404/HTML error page, is not valid OpenAPI/Swagger JSON-YAML, or TempDir is not writable.

Common situations: Spec endpoint behind authentication; corporate proxy or TLS interception mangling the fetch; typo'd spec URL; mode mismatch (Swagger 2.0 spec fed with -im openapi or vice versa); -temp-dir pointing to a read-only location; the ExecutionId-scoped dialer (protocolstate) restricting network access for SDK runs.

Related errors


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