Summary
The sentence at draft-vasters-json-structure-core.md line 1172 reads as a prohibition on "type": "array" root types, which is almost certainly not what it means and is not what the SDK implements.
The text
Section Prohibition of Top-Level Unions (#prohibition-of-top-level-unions):
- The root of a JSON Structure document MUST NOT be an array.
- If a type union is desired as the type of the root of a document instance, the
$root keyword MUST be used to designate a type union as the root type.
Read in section context, the first bullet means the root JSON value of the schema document must not be a JSON array — because that is how a union is written (["string", "null"]). Read on its own, out of context, it says a document's root type must not be of type array.
The out-of-context reading is the one people will land on, because the bullet does not mention unions at all, and the section heading is above the fold when the bullet is cited or linked directly.
Why it should be reworded rather than kept
The in-context meaning is already stated normatively, and more clearly, at line 806:
The root of a JSON Structure document MUST be a JSON object.
So the first bullet adds nothing except the misreading. It can be deleted, or rewritten to say what it means:
- A type union MUST NOT be declared at the root level, because the root of a JSON Structure document MUST be a JSON object.
The SDK agrees that type: array roots are fine
Probed against JSONStructureSchemaCoreValidator(extended=True, allow_dollar=True) from sdk/python, all of these validate clean:
| Root form |
Result |
{"type": "object", "properties": {...}} |
OK |
{"type": "array", "items": {"type": "string"}} |
OK |
{"type": "array", "items": {"type": "object", ...}} |
OK |
{"type": "string"} |
OK |
{"type": "int32"} |
OK |
{"type": "set", "items": {...}} |
OK |
{"type": "map", "values": {...}} |
OK |
{"$root": "#/definitions/Items"} -> array type |
OK |
Non-object root types, including array, bind without $root today. If that is the intent — and line 806 plus the type keyword description at line 824 suggest it is — the text should stop implying otherwise.
Separate finding in the same section: the SDK is too lenient on top-level unions
The second bullet is a genuine normative rule, and the SDK does not enforce it:
{
"$schema": "https://json-structure.org/meta/core/v0/#",
"$id": "https://example.com/probe",
"name": "Probe",
"type": ["string", "null"]
}
This validates clean, but the spec says a root union MUST go through $root. Either the validator needs the check, or the rule needs to relax — worth deciding alongside the rewording, since both bullets are in the same three lines.
Motivation
Surfaced while drafting the JSON Structure / MCP binding. MCP places no root-type constraint on outputSchema, and tools that return arrays are common. The current wording forced a defensive caveat into the binding draft restricting outputSchema roots to objects. If line 1172 means what the section context says it means, that caveat is unnecessary and array-returning tools bind fine as-is.
Summary
The sentence at
draft-vasters-json-structure-core.mdline 1172 reads as a prohibition on"type": "array"root types, which is almost certainly not what it means and is not what the SDK implements.The text
Section Prohibition of Top-Level Unions (
#prohibition-of-top-level-unions):Read in section context, the first bullet means the root JSON value of the schema document must not be a JSON array — because that is how a union is written (
["string", "null"]). Read on its own, out of context, it says a document's root type must not be of typearray.The out-of-context reading is the one people will land on, because the bullet does not mention unions at all, and the section heading is above the fold when the bullet is cited or linked directly.
Why it should be reworded rather than kept
The in-context meaning is already stated normatively, and more clearly, at line 806:
So the first bullet adds nothing except the misreading. It can be deleted, or rewritten to say what it means:
The SDK agrees that
type: arrayroots are fineProbed against
JSONStructureSchemaCoreValidator(extended=True, allow_dollar=True)fromsdk/python, all of these validate clean:{"type": "object", "properties": {...}}{"type": "array", "items": {"type": "string"}}{"type": "array", "items": {"type": "object", ...}}{"type": "string"}{"type": "int32"}{"type": "set", "items": {...}}{"type": "map", "values": {...}}{"$root": "#/definitions/Items"}-> array typeNon-object root types, including
array, bind without$roottoday. If that is the intent — and line 806 plus thetypekeyword description at line 824 suggest it is — the text should stop implying otherwise.Separate finding in the same section: the SDK is too lenient on top-level unions
The second bullet is a genuine normative rule, and the SDK does not enforce it:
{ "$schema": "https://json-structure.org/meta/core/v0/#", "$id": "https://example.com/probe", "name": "Probe", "type": ["string", "null"] }This validates clean, but the spec says a root union MUST go through
$root. Either the validator needs the check, or the rule needs to relax — worth deciding alongside the rewording, since both bullets are in the same three lines.Motivation
Surfaced while drafting the JSON Structure / MCP binding. MCP places no root-type constraint on
outputSchema, and tools that return arrays are common. The current wording forced a defensive caveat into the binding draft restrictingoutputSchemaroots to objects. If line 1172 means what the section context says it means, that caveat is unnecessary and array-returning tools bind fine as-is.