{"record":{"id":"289bb5259fa332ba","repo":"projectdiscovery/nuclei","slug":"downloaded-content-is-not-valid-json-w","errorCode":null,"errorMessage":"downloaded content is not valid JSON: %w","messagePattern":"downloaded content is not valid JSON: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/input/formats/openapi/downloader.go","lineNumber":66,"sourceCode":"\t}\n\n\tdefer func() {\n\t\t_ = resp.Body.Close()\n\t}()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn \"\", fmt.Errorf(\"HTTP %d when downloading OpenAPI spec\", resp.StatusCode)\n\t}\n\n\tbodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, maxSpecSizeBytes))\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to read response body\")\n\t}\n\n\t// Validate it's a valid JSON and has OpenAPI structure\n\tvar spec map[string]interface{}\n\tif err := json.Unmarshal(bodyBytes, &spec); err != nil {\n\t\treturn \"\", fmt.Errorf(\"downloaded content is not valid JSON: %w\", err)\n\t}\n\n\t// Check if it's an OpenAPI 3.0 spec\n\tif openapi, exists := spec[\"openapi\"]; exists {\n\t\tif openapiStr, ok := openapi.(string); ok && strings.HasPrefix(openapiStr, \"3.\") {\n\t\t\t// Valid OpenAPI 3.0 spec\n\t\t} else {\n\t\t\treturn \"\", fmt.Errorf(\"not a valid OpenAPI 3.0 spec (found version: %v)\", openapi)\n\t\t}\n\t} else {\n\t\treturn \"\", fmt.Errorf(\"not an OpenAPI spec (missing 'openapi' field)\")\n\t}\n\n\t// Extract host from URL for server configuration\n\tparsedURL, err := url.Parse(urlStr)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to parse URL\")\n\t}","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/input/formats/openapi/downloader.go#L48-L84","documentation":"The OpenAPI spec URL returned HTTP 200 but the body is not parseable JSON. The downloader reads at most 10MB (io.LimitReader) and unmarshals into map[string]interface{}; any failure is wrapped with the underlying encoding/json error. Common causes: an HTML page (docs UI or login redirect served with 200), a YAML or plain-text body, a BOM, or a document truncated by the 10MB cap.","triggerScenarios":"URL ends in .json but content negotiation returns HTML; SSO/login portals answering 200 with an HTML shell; a YAML body served under a .json name; specs larger than 10MB cut mid-document by the LimitReader; gzip/deflate double-encoding producing binary bytes.","commonSituations":"Docs sites where /openapi.json actually renders a viewer page; reverse proxies that inject scripts or cookies notices into responses; misconfigured static hosting guessing content type; very large machine-generated specs.","solutions":["Fetch the URL with curl and inspect the raw body to see what is actually served","If the body is YAML, switch to `-im swagger` (accepts .yaml/.yml) or convert the file to JSON and use `nuclei -l spec.json`","Ensure the URL returns the raw spec document, not an HTML viewer or login page","If the spec exceeds 10MB, split it or trim unused paths, then feed it as a local file"],"exampleFix":"# before: .json URL that actually serves YAML\nnuclei -im openapi -u https://host/spec.json\n\n# after: download locally and convert\ncurl -s https://host/spec.json -o spec.yaml\n# convert YAML->JSON (e.g. yq -o=json '.' spec.yaml > spec.json)\nnuclei -l spec.json","handlingStrategy":"validation","validationCode":"resp, err := http.Get(url)\nif err != nil {\n    return err\n}\nbody, _ := io.ReadAll(io.LimitReader(resp.Body, 10<<20))\nif !json.Valid(body) {\n    return fmt.Errorf(\"body at %s is not JSON; inspect it before passing to nuclei\", url)\n}","typeGuard":"func looksLikeOpenAPIJSON(body []byte) bool {\n    var spec map[string]json.RawMessage\n    if err := json.Unmarshal(body, &spec); err != nil {\n        return false\n    }\n    _, hasOpenAPI := spec[\"openapi\"]\n    _, hasSwagger := spec[\"swagger\"]\n    return hasOpenAPI || hasSwagger\n}","tryCatchPattern":"if err := downloader.Download(...); err != nil {\n    if strings.Contains(err.Error(), \"not valid JSON\") {\n        // body is HTML/YAML: fetch manually, convert, then use a local file\n    }\n}","preventionTips":["Verify the spec URL serves raw JSON with curl before wiring it into automation","Keep specs under 10MB or feed them as local files","Convert YAML specs to JSON (yq -o=json) before using openapi mode"],"tags":["openapi","json","parsing","network","download"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}