{"record":{"id":"1398c787efe7de80","repo":"projectdiscovery/nuclei","slug":"url-does-not-appear-to-be-an-openapi-json-spec","errorCode":null,"errorMessage":"URL does not appear to be an OpenAPI JSON spec","messagePattern":"URL does not appear to be an OpenAPI JSON spec","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/input/formats/openapi/downloader.go","lineNumber":31,"sourceCode":"\n\t\"github.com/pkg/errors\"\n\t\"github.com/projectdiscovery/nuclei/v3/pkg/input/formats\"\n\t\"github.com/projectdiscovery/retryablehttp-go\"\n)\n\n// OpenAPIDownloader implements the SpecDownloader interface for OpenAPI 3.0 specs\ntype OpenAPIDownloader struct{}\n\n// NewDownloader creates a new OpenAPI downloader\nfunc NewDownloader() formats.SpecDownloader {\n\treturn &OpenAPIDownloader{}\n}\n\n// This function downloads an OpenAPI 3.0 spec from the given URL and saves it to tmpDir\nfunc (d *OpenAPIDownloader) Download(urlStr, tmpDir string, httpClient *retryablehttp.Client) (string, error) {\n\t// Validate URL format, OpenAPI 3.0 specs are typically JSON\n\tif !strings.HasSuffix(urlStr, \".json\") {\n\t\treturn \"\", fmt.Errorf(\"URL does not appear to be an OpenAPI JSON spec\")\n\t}\n\n\tconst maxSpecSizeBytes = 10 * 1024 * 1024 // 10MB\n\n\t// Use provided httpClient or create a fallback\n\tvar client *http.Client\n\tif httpClient != nil {\n\t\tclient = httpClient.HTTPClient\n\t} else {\n\t\t// Fallback to simple client if no httpClient provided\n\t\tclient = &http.Client{Timeout: 30 * time.Second}\n\t}\n\n\tresp, err := client.Get(urlStr)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to download OpenAPI spec\")\n\t}\n","sourceCodeStart":13,"sourceCodeEnd":49,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/input/formats/openapi/downloader.go#L13-L49","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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)"],"exampleFix":"# before\nnuclei -im openapi -u https://api.example.com/api-docs\n\n# after\nnuclei -im openapi -u https://api.example.com/openapi.json","handlingStrategy":"validation","validationCode":"func isOpenAPIDownloadable(u string) bool {\n    if !strings.HasPrefix(u, \"http://\") && !strings.HasPrefix(u, \"https://\") {\n        return false\n    }\n    return strings.HasSuffix(u, \".json\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := downloader.Download(u, tmp, client); err != nil {\n    if strings.Contains(err.Error(), \"does not appear to be an OpenAPI JSON spec\") {\n        // fall back: download manually or switch to swagger mode for .yaml/.yml\n    }\n}","preventionTips":["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"],"tags":["openapi","url","input-mode","download"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}