projectdiscovery/nuclei · error
URL does not appear to be an OpenAPI JSON spec
Error message
URL does not appear to be an OpenAPI JSON spec
What it means
OpenAPIDownloader.Download (pkg/input/formats/openapi/downloader.go) rejects any URL that does not end exactly with `.json` (case-sensitive strings.HasSuffix, before any HTTP request is made). The check exists because this downloader only understands OpenAPI 3.0 JSON documents, so a URL without the .json suffix is treated as not an OpenAPI JSON spec.
Source
Thrown at pkg/input/formats/openapi/downloader.go:31
"github.com/pkg/errors"
"github.com/projectdiscovery/nuclei/v3/pkg/input/formats"
"github.com/projectdiscovery/retryablehttp-go"
)
// OpenAPIDownloader implements the SpecDownloader interface for OpenAPI 3.0 specs
type OpenAPIDownloader struct{}
// NewDownloader creates a new OpenAPI downloader
func NewDownloader() formats.SpecDownloader {
return &OpenAPIDownloader{}
}
// This function downloads an OpenAPI 3.0 spec from the given URL and saves it to tmpDir
func (d *OpenAPIDownloader) Download(urlStr, tmpDir string, httpClient *retryablehttp.Client) (string, error) {
// Validate URL format, OpenAPI 3.0 specs are typically JSON
if !strings.HasSuffix(urlStr, ".json") {
return "", fmt.Errorf("URL does not appear to be an OpenAPI JSON spec")
}
const maxSpecSizeBytes = 10 * 1024 * 1024 // 10MB
// Use provided httpClient or create a fallback
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")
}
View on GitHub (pinned to 265b3a3dec)
Solutions
- Point -u at the raw spec URL ending in .json (open the docs UI and copy the spec link behind it)
- If the spec is YAML or Swagger 2.x, use `-im swagger`, which accepts .json, .yaml and .yml
- Strip query strings and fragments from the URL
- If the server cannot serve a .json-suffixed URL, download the spec manually and pass the local file with `nuclei -l spec.json` (format is auto-detected)
Example fix
# before nuclei -im openapi -u https://api.example.com/api-docs # after nuclei -im openapi -u https://api.example.com/openapi.json
Defensive patterns
Strategy: validation
Validate before calling
func isOpenAPIDownloadable(u string) bool {
if !strings.HasPrefix(u, "http://") && !strings.HasPrefix(u, "https://") {
return false
}
return strings.HasSuffix(u, ".json")
} Try / catch
if _, err := downloader.Download(u, tmp, client); err != nil {
if strings.Contains(err.Error(), "does not appear to be an OpenAPI JSON spec") {
// fall back: download manually or switch to swagger mode for .yaml/.yml
}
} Prevention
- Bookmark the raw spec URL (ends in .json), not the docs UI route
- Strip query strings and fragments from spec URLs
- Prefer local files (`nuclei -l spec.json`) when the server cannot serve a .json-suffixed URL
When it happens
Trigger: `nuclei -im openapi -u https://host/api-docs` (no extension); a YAML spec URL like https://host/openapi.yaml; uppercase .JSON; URLs with query strings or fragments appended after the filename (openapi.json?v=2); pasting a Swagger UI page URL instead of the raw spec link.
Common situations: Copying the interactive docs URL (e.g. /swagger-ui or /api-docs) rather than the raw spec; specs served by gateways without file extensions; URLs carrying auth query tokens; Windows-style casing .JSON.
Related errors
- not an OpenAPI spec (missing 'openapi' field)
- URL does not appear to be a Swagger spec (supported: %v)
- HTTP %d when downloading OpenAPI spec
- downloaded content is not valid JSON: %w
- not a valid OpenAPI 3.0 spec (found version: %v)
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/1398c787efe7de80.
Report an issue: GitHub.