Skip to content

Ambiguous: "The root of a JSON Structure document MUST NOT be an array" reads as prohibiting type: array roots #33

Description

@clemensv

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions