Swagger UI shows "Unable to render this definition" when it cannot find a version field it recognizes. The full message reads: The provided definition does not specify a valid version field. Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: "2.0" and openapi: 3.0.x, openapi: 3.1.x, or openapi: 3.2.x (for example, openapi: 3.2.0). The most common cause we found is an unquoted number. In YAML, swagger: 2.0 is the number 2 and openapi: 3.0 is the number 3, and Swagger UI rejects both.
What Swagger UI accepts
We loaded 12 spec variants into Swagger UI 5.33.1 in Chrome 152 and recorded whether each one rendered. Every variant had the same single operation, GET /ping, and differed only in the version line. The spec was passed as a JavaScript object, which is what Swagger UI receives after it parses JSON or YAML.
| Version line | Result in Swagger UI 5.33.1 |
|---|---|
| swagger: "2.0" | Renders (labeled OAS 2.0) |
| swagger: 2 (a number) | Fails with the version error |
| swagger: "1.2" | Fails with the version error |
| openapi: "3.0.0" | Renders (labeled OAS 3.0) |
| openapi: "3.0.3" | Renders (labeled OAS 3.0) |
| openapi: "3.0" (no patch number) | Fails with the version error |
| openapi: 3 (a number) | Fails with the version error |
| openapi: "3.1.0" | Renders (labeled OAS 3.1) |
| openapi: "3.1.1" | Renders (labeled OAS 3.1) |
| openapi: "3.2.0" | Renders (labeled OAS 3.2) |
| No version field at all | Fails with the version error |
| openapi: "3.0.3" with no paths | Renders the title and shows "No operations defined in spec!" (not an error) |
The version must be a string, and an OpenAPI 3 version needs all three parts. A spec with no paths is not an error: it renders its title and a notice, so an empty page with that notice is a different problem from this one.
The YAML trap: unquoted versions become numbers
The version field is a string, but YAML chooses a type by reading the text. A value like 3.0.3 is not a valid number, so it stays a string. A value like 3.0 is a valid number, so the parser turns it into the number 3. We parsed six lines with js-yaml 4.1.1 and checked the result type:
| YAML line | Parsed as |
|---|---|
| openapi: 3.0 | number 3 |
| openapi: 3.0.0 | string "3.0.0" |
| openapi: "3.0" | string "3.0" |
| swagger: 2.0 | number 2 |
| swagger: "2.0" | string "2.0" |
| openapi: 3.1.0 | string "3.1.0" |
This is why a file that looks correct to a human fails. swagger: 2.0 reads like the right value, but the parser hands Swagger UI the number 2, which is not the string "2.0". The Swagger documentation writes the field as swagger: "2.0", with quotes, and the OpenAPI Specification says the openapi field must be the version number of the specification and that tooling should use it to interpret the document. A number does not satisfy that.
The fix is two habits: quote Swagger 2.0 versions, and write all three parts of an OpenAPI 3 version.
# Fails in Swagger UI: parsed as numbers
swagger: 2.0
openapi: 3.0
# Works: strings with all three parts
swagger: "2.0"
openapi: 3.0.3Check what your parser sees
If you cannot tell whether your file is affected, ask a parser. For a JSON spec, jq prints the type of the version field:
jq '.openapi // .swagger | type' openapi.json
# "string" is correct. "number" or "null" explains the error.For a YAML spec, parse it the way a tool would. This one-liner needs js-yaml installed (npm install js-yaml):
node -e "const y=require('js-yaml');const d=y.load(require('fs').readFileSync('openapi.yaml','utf8'));console.log(typeof d.openapi, d.openapi, typeof d.swagger, d.swagger)"
# Expected for a valid OpenAPI 3 file: string 3.0.3 undefined undefinedIf a framework generates the spec, request the generated JSON and run the jq line on that response. Generators write JSON, where the version is already a string, so the YAML trap usually applies to specs that people write and edit by hand.
Catch it before it ships
A version typo costs nothing to find in a pull request and a lot to find after the docs page goes live. The script below reads a spec with js-yaml, which also parses JSON, and exits with an error unless the version is a string that matches what Swagger UI 5.33.1 accepted in our test: "2.0" for Swagger 2.0, or 3.0.x, 3.1.x and 3.2.x for OpenAPI 3. We ran it against five files. The files with openapi: 3.0 and swagger: 2.0 failed with "number 3" and "number 2", the file with no version failed, and the files with openapi: 3.0.3 and swagger: "2.0" passed.
import { readFileSync } from "node:fs";
import yaml from "js-yaml";
const file = process.argv[2];
const spec = yaml.load(readFileSync(file, "utf8"));
const version = spec.openapi ?? spec.swagger;
const ok = typeof version === "string" && (/^3\.[0-2]\.\d+$/.test(version) || version === "2.0");
if (!ok) {
console.error(`${file}: version field is ${typeof version} ${JSON.stringify(version)}`);
process.exit(1);
}
console.log(`${file}: ${version} ok`);A version check proves only that the first line is right. Pair it with a full validation pass, as described in the guide to validating Swagger and OpenAPI specs, so structural mistakes fail the build too.
Other causes reported on GitHub
The long GitHub threads on this error are mostly unresolved, so treat the items below as leads and not guaranteed fixes.
If the version line is correct
Work down the list.
| Scenario | Recommendation | Alternative |
|---|---|---|
| The spec URL returns something other than a spec | Open the spec URL in a new tab. An HTML page, a login redirect or an error body has no version field. How to get the OpenAPI JSON from a Swagger UI page lists the default spec URLs for common frameworks. | — |
| The file works in Swagger Editor but fails on a deployed Swagger UI | A collaborator in an OpenAPI Specification discussion (#2852) suggested the URL passed to the UI may be one it cannot parse. Type the full URL next to the Explore button and click the Invalid badge to see which URL the validator tried. | — |
| swagger-ui-react keeps showing the first spec you gave it | One reporter in swagger-ui discussion #8586 saw the component keep the first spec after switching between JSON and YAML. The thread has no confirmed fix. Passing a fresh spec object, or remounting the component, is worth a try; we did not test it. | — |
| You have a 3.1 or 3.2 file and an older Swagger UI | Swagger UI 5.33.1 rendered 3.0, 3.1 and 3.2 in our test. GitHub reports say older builds reject some versions. Update swagger-ui-dist or the Swagger package your framework bundles. | — |
| The page renders but shows No operations defined in spec! | The version is fine. The paths object is missing or empty. | — |
Load the spec in APIForge to split the problem
APIForge's parser does not need a valid version field. We ran nine of the variants above through it, including swagger: 2 as a number, openapi: 3 as a number, "1.2", and no version field at all. Every one loaded with its single endpoint. That gives you a quick way to split the problem in two. If APIForge lists your operations, your paths and schemas are readable, and the version line or the way Swagger UI receives the file is the likely culprit. If APIForge fails as well, the file is broken at a deeper level, and the guide to validating Swagger and OpenAPI specs and the list of common OpenAPI errors are the next stop.
APIForge does not flag the invalid version, so you still need the check from the previous section. Paste your file or URL into the OpenAPI validator or the Swagger 2.0 validator to load it, then use the API quality score to see design problems once it parses. If you are unsure why one file says swagger and another says openapi, Swagger vs OpenAPI explains the naming and version history. An editor that validates as you type catches a bad version line earlier; APIForge vs Swagger Editor compares the two tools.