Repository navigation
Description
The schema at https://openapi.vercel.sh/vercel.json declares draft-04 but uses keywords that do not exist in draft-04, so it fails validation against the metaschema it names. Tools that honour $schema reject the document rather than applying it.
Reproduce
curl -sO https://openapi.vercel.sh/vercel.jsonimport json, jsonschema
s = json.load(open("vercel.json"))
print(s["$schema"]) # http://json-schema.org/draft-04/schema#
jsonschema.Draft4Validator.check_schema(s)jsonschema.exceptions.SchemaError: {'type': 'object', 'additionalProperties': False,
'required': ['root'], 'properties': {'root': {'description': 'Path to the servic...
Behaviour across metaschemas (jsonschema 4.26.0), same file, unchanged:
| metaschema | result |
|---|---|
| draft-04 (the one it declares) | REJECTED |
| draft-06 | accepted |
| draft-07 | accepted |
| 2020-12 | accepted |
Keywords that force this
Counting occurrences in the served file:
| keyword | count | introduced in |
|---|---|---|
const |
21 | draft-06 |
if / then |
15 / 15 | draft-07 |
propertyNames |
2 | draft-06 |
exclusiveMinimum |
3 | boolean in draft-04, numeric from draft-06 |
exclusiveMinimum is the one worth pausing on: in draft-04 it is a boolean modifier on minimum; from draft-06 it is a number. It is not merely unrecognised here, it means something different.
Why it matters
Editors resolve this URL from $schema and from schema catalogues, and apply it while you type. A strict loader refuses the whole document at that point, which means no completion and no diagnostics — a config file with a typo looks exactly like a config file without one. Ajv in strictSchema mode is in the same position, and so is every Go/Java/Rust validator that reads $schema to pick its dialect.
Two things make this easy to miss from the inside: the file is consumed by Vercel's own tooling through a purpose-built reader (packages/config/scripts/generate-types.ts parses it by hand for code generation) rather than a general validator, and Vercel's TypeScript reader already assumes the newer keywords.
Suggested fix
Change the dialect declaration to the one the content already uses:
- "$schema": "http://json-schema.org/draft-04/schema#",
+ "$schema": "http://json-schema.org/draft-07/schema#",No other change is required. draft-07 accepts everything currently in the file, and it accepts the $data references only as opaque annotations, which is the same treatment they receive today. If the intent is to keep $data functional, note that it is an Ajv extension rather than a spec keyword, so a $comment saying so would help other consumers.
How this came up
I wrote a small mutation tester for validators — it feeds a validator inputs that ought to be rejected and reports what it lets through. Pointing it at served JSON schemas surfaced this one as a special case: the schema does not merely accept something it should reject, it cannot load at all under the dialect it names. The tool is https://github.com/simin-yuan/greencheck (MIT, no dependencies); the reproduction above stands on its own without it.
Activity
simin-yuan commentedon Sep 24, 2026
Verified independently, with a one-command repro.
I re-ran this against a real validator instead of eyeballing it: check-jsonschema 0.38.0 / jsonschema 4.26.0, schema fetched from https://openapi.vercel.sh/vercel.json today.
So yes, it fails against the metaschema it names. The failure is narrower than the title suggests, and worth stating precisely: only the 3 numeric
exclusiveMinimumuses actually break draft-04, because draft-04 requires a boolean there. Same pointer three times, underfunctions,services.*.functionsandexperimentalServicesV2.*.functions.const(21 uses),if/then(15 each) andpropertyNames(2) are also not draft-04 keywords. Those do not error, because a draft-04 validator simply ignores unknown keywords. They just silently do nothing for editors that trust the declared dialect, which is a weaker gap than the numeric exclusiveMinimum.Minimal fix, also verified: the schema has no
idkeywords that would need migrating, so switching the declared dialect is a one-line change.With that change the same command exits 0 against the draft-07 metaschema. Draft-07 covers every keyword used here.
No affiliation with Vercel. Just a schema/validator mismatch I ran into while using this schema.