{"record":{"id":"2ab6c81192d94a0a","repo":"projectdiscovery/nuclei","slug":"not-a-swagger-spec-missing-swagger-field","errorCode":null,"errorMessage":"not a Swagger spec (missing 'swagger' field)","messagePattern":"not a Swagger spec \\(missing 'swagger' field\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/input/formats/swagger/downloader.go","lineNumber":93,"sourceCode":"\n\t// Try JSON first\n\tif err := json.Unmarshal(bodyBytes, &spec); err != nil {\n\t\t// Then try YAML\n\t\tif err := yaml.Unmarshal(bodyBytes, &spec); err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"downloaded content is neither valid JSON nor YAML: %w\", err)\n\t\t}\n\t\tisYAML = true\n\t}\n\n\t// Validate it's a Swagger 2.0 spec\n\tif swagger, exists := spec[\"swagger\"]; exists {\n\t\tif swaggerStr, ok := swagger.(string); ok && strings.HasPrefix(swaggerStr, \"2.\") {\n\t\t\t// Valid Swagger 2.0 spec\n\t\t} else {\n\t\t\treturn \"\", fmt.Errorf(\"not a valid Swagger 2.0 spec (found version: %v)\", swagger)\n\t\t}\n\t} else {\n\t\treturn \"\", fmt.Errorf(\"not a Swagger spec (missing 'swagger' field)\")\n\t}\n\n\t// Extract host from URL for host configuration\n\tparsedURL, err := url.Parse(urlStr)\n\tif err != nil {\n\t\treturn \"\", errors.Wrap(err, \"failed to parse URL\")\n\t}\n\n\thost := parsedURL.Host\n\tscheme := parsedURL.Scheme\n\tif scheme == \"\" {\n\t\tscheme = \"https\"\n\t}\n\n\t// Add host if missing\n\tif _, exists := spec[\"host\"]; !exists {\n\t\tspec[\"host\"] = host\n\t}","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/projectdiscovery/nuclei/blob/265b3a3dec374741614e342f813c10f8b38d2bb7/pkg/input/formats/swagger/downloader.go#L75-L111","documentation":"The downloaded document is valid JSON/YAML but has no top-level `swagger` key, the mandatory marker of a Swagger 2.0 document. Usually this means the document is an OpenAPI 3.x spec (marker: `openapi`) or simply not a spec at all (any parsed JSON/YAML document).","triggerScenarios":"Passing an OpenAPI 3 spec to `-im swagger`; pointing at an arbitrary JSON config or YAML metadata file; docs-viewer JSON envelopes.","commonSituations":"Not knowing the API's spec generation (modern generators emit 3.x by default); wrong URL guessed from documentation; mixed-platform spec repos.","solutions":["If the document has an `openapi: 3.x` key, run with `-im openapi`","Open the URL and verify the first keys: Swagger 2.0 must start with swagger: \"2.0\"","Locate the actual v2 spec URL (older gateways usually expose /swagger.json)","If it is not a spec at all, find the correct document before scanning"],"exampleFix":"# before (3.x spec -> missing 'swagger' field)\nnuclei -im swagger -u https://host/spec.yaml\n\n# after\nnuclei -im openapi -u https://host/spec.json","handlingStrategy":"validation","validationCode":"keys := make([]string, 0)\nfor k := range spec {\n    keys = append(keys, k)\n}\nif _, ok := spec[\"swagger\"]; !ok {\n    return fmt.Errorf(\"no 'swagger' key (has: %v); wrong mode or not a spec\", keys)\n}","typeGuard":"func sniffSpecMode(spec map[string]any) string {\n    if v, _ := spec[\"swagger\"].(string); strings.HasPrefix(v, \"2.\") {\n        return \"swagger\"\n    }\n    if v, _ := spec[\"openapi\"].(string); strings.HasPrefix(v, \"3.\") {\n        return \"openapi\"\n    }\n    return \"\"\n}","tryCatchPattern":"if strings.Contains(err.Error(), \"missing 'swagger' field\") {\n    // sniff keys: an 'openapi' key means switch to -im openapi; otherwise find the real spec URL\n}","preventionTips":["Sniff the marker key once and pick the mode programmatically","Store validated spec URLs per environment","Do not scan arbitrary JSON/YAML URLs as specs"],"tags":["swagger","spec-validation","input-mode","openapi"],"backgroundTag":null,"analyzedSha":"265b3a3dec374741614e342f813c10f8b38d2bb7","analyzedAt":"2026-08-15T20:05:51.855Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}