projectdiscovery/nuclei · error

not a Swagger spec (missing 'swagger' field)

Error message

not a Swagger spec (missing 'swagger' field)

What it means

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).

Source

Thrown at pkg/input/formats/swagger/downloader.go:93

	// Try JSON first
	if err := json.Unmarshal(bodyBytes, &spec); err != nil {
		// Then try YAML
		if err := yaml.Unmarshal(bodyBytes, &spec); err != nil {
			return "", fmt.Errorf("downloaded content is neither valid JSON nor YAML: %w", err)
		}
		isYAML = true
	}

	// Validate it's a Swagger 2.0 spec
	if swagger, exists := spec["swagger"]; exists {
		if swaggerStr, ok := swagger.(string); ok && strings.HasPrefix(swaggerStr, "2.") {
			// Valid Swagger 2.0 spec
		} else {
			return "", fmt.Errorf("not a valid Swagger 2.0 spec (found version: %v)", swagger)
		}
	} else {
		return "", fmt.Errorf("not a Swagger spec (missing 'swagger' field)")
	}

	// Extract host from URL for host 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 host if missing
	if _, exists := spec["host"]; !exists {
		spec["host"] = host
	}

View on GitHub (pinned to 265b3a3dec)

Solutions

  1. If the document has an `openapi: 3.x` key, run with `-im openapi`
  2. Open the URL and verify the first keys: Swagger 2.0 must start with swagger: "2.0"
  3. Locate the actual v2 spec URL (older gateways usually expose /swagger.json)
  4. If it is not a spec at all, find the correct document before scanning

Example fix

# before (3.x spec -> missing 'swagger' field)
nuclei -im swagger -u https://host/spec.yaml

# after
nuclei -im openapi -u https://host/spec.json
Defensive patterns

Strategy: validation

Validate before calling

keys := make([]string, 0)
for k := range spec {
    keys = append(keys, k)
}
if _, ok := spec["swagger"]; !ok {
    return fmt.Errorf("no 'swagger' key (has: %v); wrong mode or not a spec", keys)
}

Type guard

func sniffSpecMode(spec map[string]any) string {
    if v, _ := spec["swagger"].(string); strings.HasPrefix(v, "2.") {
        return "swagger"
    }
    if v, _ := spec["openapi"].(string); strings.HasPrefix(v, "3.") {
        return "openapi"
    }
    return ""
}

Try / catch

if strings.Contains(err.Error(), "missing 'swagger' field") {
    // sniff keys: an 'openapi' key means switch to -im openapi; otherwise find the real spec URL
}

Prevention

When it happens

Trigger: Passing an OpenAPI 3 spec to `-im swagger`; pointing at an arbitrary JSON config or YAML metadata file; docs-viewer JSON envelopes.

Common situations: Not knowing the API's spec generation (modern generators emit 3.x by default); wrong URL guessed from documentation; mixed-platform spec repos.

Related errors


AI-assisted analysis of projectdiscovery/nuclei@265b3a3dec (2026-08-15). Data as JSON: /api/errors/2ab6c81192d94a0a. Report an issue: GitHub.