{"record":{"id":"fdab74f06a68c402","repo":"projectdiscovery/nuclei","slug":"url-does-not-appear-to-be-a-swagger-spec-supporte","errorCode":null,"errorMessage":"URL does not appear to be a Swagger spec (supported: %v)","messagePattern":"URL does not appear to be a Swagger spec \\(supported: (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/input/formats/swagger/downloader.go","lineNumber":40,"sourceCode":"\n// NewDownloader creates a new Swagger downloader\nfunc NewDownloader() formats.SpecDownloader {\n\treturn &SwaggerDownloader{}\n}\n\n// This function downloads a Swagger 2.0 spec from the given URL and saves it to tmpDir\nfunc (d *SwaggerDownloader) Download(urlStr, tmpDir string, httpClient *retryablehttp.Client) (string, error) {\n\t// Swagger can be JSON or YAML\n\tsupportedExts := d.SupportedExtensions()\n\tisSupported := false\n\tfor _, ext := range supportedExts {\n\t\tif strings.HasSuffix(urlStr, ext) {\n\t\t\tisSupported = true\n\t\t\tbreak\n\t\t}\n\t}\n\tif !isSupported {\n\t\treturn \"\", fmt.Errorf(\"URL does not appear to be a Swagger spec (supported: %v)\", supportedExts)\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 Swagger spec\")\n\t}\n","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/input/formats/swagger/downloader.go#L22-L58","documentation":"SwaggerDownloader.Download (pkg/input/formats/swagger/downloader.go) rejects URLs whose path does not end with one of the supported extensions reported by SupportedExtensions(): .json, .yaml, or .yml (case-sensitive strings.HasSuffix, checked before any request). Swagger mode must know the document format in advance, hence the extension gate.","triggerScenarios":"`nuclei -im swagger -u https://host/swagger` (no extension); URL with query string after the filename (swagger.json?access=x); uppercase .YAML; extension-less gateway routes like /v2/spec.","commonSituations":"Spec URLs behind API gateways or doc portals without file extensions; URLs with auth query parameters; copy-pasting the docs UI route instead of the raw spec.","solutions":["Use a URL ending in .json, .yaml or .yml","Strip query strings and fragments","If the server cannot serve an extensioned URL, download manually (curl -o spec.yaml) and run `nuclei -l spec.yaml`","Check the printed supported list in the error to confirm the exact suffixes accepted"],"exampleFix":"# before\nnuclei -im swagger -u https://api.example.com/v2/spec\n\n# after\ncurl -s https://api.example.com/v2/spec -o spec.json\nnuclei -l spec.json -im swagger","handlingStrategy":"validation","validationCode":"func isSwaggerDownloadable(u string) bool {\n    for _, ext := range []string{\".json\", \".yaml\", \".yml\"} {\n        if strings.HasSuffix(u, ext) {\n            return true\n        }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"if _, err := downloader.Download(u, tmp, client); err != nil {\n    if strings.Contains(err.Error(), \"does not appear to be a Swagger spec\") {\n        // download manually and pass the local file: nuclei -l spec.json -im swagger\n    }\n}","preventionTips":["Use extensioned spec URLs (.json/.yaml/.yml)","Keep a local mirror of gateway-served specs for scanning","Strip query strings from spec URLs"],"tags":["swagger","url","input-mode","download"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}