projectdiscovery/nuclei · error
not an OpenAPI spec (missing 'openapi' field)
Error message
not an OpenAPI spec (missing 'openapi' field)
What it means
The downloaded URL returned valid JSON but the document has no top-level `openapi` key, which is the mandatory version marker of an OpenAPI 3.x spec. The downloader therefore cannot classify it. Typical bodies: a Swagger 2.0 doc (which uses `swagger:`), an unrelated JSON config/document, or a JSON wrapper served by a docs viewer.
Source
Thrown at pkg/input/formats/openapi/downloader.go:77
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 {
return "", fmt.Errorf("not a valid OpenAPI 3.0 spec (found version: %v)", openapi)
}
} else {
return "", fmt.Errorf("not an OpenAPI spec (missing 'openapi' field)")
}
// Extract host from URL for server configuration
parsedURL, err := url.Parse(urlStr)
if err != nil {
return "", errors.Wrap(err, "failed to parse URL")
}
host := parsedURL.Host
scheme := parsedURL.Scheme
if scheme == "" {
scheme = "https"
}
// Add servers section if missing or empty
servers, exists := spec["servers"]
if !exists || servers == nil {
spec["servers"] = []map[string]interface{}{{"url": scheme + "://" + host}}
} else if serverList, ok := servers.([]interface{}); ok && len(serverList) == 0 {View on GitHub (pinned to 265b3a3dec)
Solutions
- If the document has `swagger: 2.x`, use `-im swagger`
- Open the URL and confirm the top-level keys: an OpenAPI 3 spec must start with "openapi": "3..."
- Locate the real spec URL from the docs UI (usually linked behind a 'download/open specification' action)
- If the JSON is an envelope, extract the inner spec object, save it locally, and run `nuclei -l spec.json`
Example fix
# before (document is Swagger 2.0 -> missing 'openapi' field) nuclei -im openapi -u https://host/spec.json # after nuclei -im swagger -u https://host/spec.json
Defensive patterns
Strategy: validation
Validate before calling
var spec map[string]any
if err := json.Unmarshal(body, &spec); err != nil {
return err
}
if _, ok := spec["openapi"]; !ok {
if _, isSwagger := spec["swagger"]; isSwagger {
return fmt.Errorf("document is Swagger 2.x; use -im swagger")
}
return fmt.Errorf("document is not an API spec")
} Type guard
func isAPIspec(spec map[string]any) (mode string, ok bool) {
if v, _ := spec["openapi"].(string); strings.HasPrefix(v, "3.") {
return "openapi", true
}
if v, _ := spec["swagger"].(string); strings.HasPrefix(v, "2.") {
return "swagger", true
}
return "", false
} Try / catch
if strings.Contains(err.Error(), "missing 'openapi' field") {
// inspect the document keys: switch to swagger mode or find the real spec URL
} Prevention
- Sniff the document's top-level key (openapi vs swagger) once and cache the right input mode
- Do not reuse docs-UI URLs as spec URLs
- Store known-good spec URLs per service in config
When it happens
Trigger: Passing a Swagger 2.0 spec to `-im openapi`; pointing at a JSON API endpoint or docs metadata file instead of the spec; specs uploaded to generic file hosts that wrap content in an envelope like {"file": ...}.
Common situations: Not knowing whether an API documents with 2.0 or 3.x and guessing the mode; specs behind discovery endpoints like /api-docs that return session JSON; copy-pasting a JSON blob from a browser pretty-print view.
Related errors
- URL does not appear to be an OpenAPI JSON spec
- not a valid OpenAPI 3.0 spec (found version: %v)
- not a Swagger spec (missing 'swagger' field)
- HTTP %d when downloading OpenAPI spec
- downloaded content is not valid JSON: %w
AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15).
Data as JSON: /api/errors/d1959ba189e28aef.
Report an issue: GitHub.