A schema may declare "$uses": ["JSONStructureAlternateNames"] and then put almost anything under altenums or descriptions without a validator objecting. The keywords are recognised as belonging to a known extension, and then not checked.
Repro
All against json-structure-check --extended from the Python SDK, with "JSONStructureAlternateNames" present in $uses.
| Schema fragment |
Spec says |
Result |
"altenums": "not-an-object" |
MUST be a JSON object |
Schema is valid. |
"altenums": {...} on a schema with no enum |
"MUST be used only with schemas that include an enum keyword" |
Schema is valid. |
"altenums": {"lang:en": {"notAnEnumValue": "x"}} |
keys map "each enumeration value (as defined in the enum array)" |
Schema is valid. |
"altnames": {"lang:en": 12345} |
values are alternate name strings |
Schema is valid. |
altenums with the extension absent from $uses is also accepted, which is a separate question but the same root cause.
For contrast, a name in $uses that no extension defines is rejected:
- #/$uses[1] [SCHEMA_USES_UNKNOWN_EXTENSION] Unknown extension 'TotallyBogusFeatureName' in $uses.
So the extension is known to the implementation; its keywords are simply not validated.
State of the code
altenums appears in no SDK's validator source. Searching the repository finds it only in python/tests/test_instance_validator.py, in a test that asserts an instance validates while the keyword is ignored.
descriptions is likewise unvalidated.
altnames has error codes defined in nine languages — SCHEMA_ALTNAMES_NOT_OBJECT and SCHEMA_ALTNAMES_VALUE_NOT_STRING, exported from each language's public error-code surface, and described in assets/error-messages.json — but only two implementations ever raise them: java/.../SchemaValidator.java (validateAltnames) and perl/lib/JSON/Structure/SchemaValidator.pm. In .NET, Go, PHP, Python, Rust, Swift, and TypeScript the constants are defined and dead.
That last point is the one I would fix first: seven SDKs publish an error code they can never emit, which is a stronger signal of intent than an absent feature would be.
Why it matters
The gap is easy to hit and silent. I annotated thirty-seven enums across a sample corpus and had to write a separate checker script to find the mistakes I made while doing it — wrong symbol keys, a missing entry, an empty label. The SDK reported every one of those schemas as valid.
Proposal
Implement schema-time validation for the Alternate Names keywords, in the shared rule set so that all languages get it:
altnames — object; every value a non-empty string. (Port the Java implementation.)
descriptions — object; every value a non-empty string.
altenums — object; every value an object; every value of that inner object a non-empty string; the enclosing schema has an enum; the inner object's keys are enum values.
The last two of those depend on questions the Alternate Names draft does not currently answer — how a non-string enum value is written as a mapping key, and whether a mapping may be partial. I have opened those separately against json-structure/alternate-names; the key-form check should follow whatever is decided there. The first three checks do not depend on anything and could land now.
Whatever lands, please add the negative cases to test-assets/ so the implementations converge rather than each inventing a subset.
A schema may declare
"$uses": ["JSONStructureAlternateNames"]and then put almost anything underaltenumsordescriptionswithout a validator objecting. The keywords are recognised as belonging to a known extension, and then not checked.Repro
All against
json-structure-check --extendedfrom the Python SDK, with"JSONStructureAlternateNames"present in$uses."altenums": "not-an-object"Schema is valid."altenums": {...}on a schema with noenumenumkeyword"Schema is valid."altenums": {"lang:en": {"notAnEnumValue": "x"}}enumarray)"Schema is valid."altnames": {"lang:en": 12345}Schema is valid.altenumswith the extension absent from$usesis also accepted, which is a separate question but the same root cause.For contrast, a name in
$usesthat no extension defines is rejected:So the extension is known to the implementation; its keywords are simply not validated.
State of the code
altenumsappears in no SDK's validator source. Searching the repository finds it only inpython/tests/test_instance_validator.py, in a test that asserts an instance validates while the keyword is ignored.descriptionsis likewise unvalidated.altnameshas error codes defined in nine languages —SCHEMA_ALTNAMES_NOT_OBJECTandSCHEMA_ALTNAMES_VALUE_NOT_STRING, exported from each language's public error-code surface, and described inassets/error-messages.json— but only two implementations ever raise them:java/.../SchemaValidator.java(validateAltnames) andperl/lib/JSON/Structure/SchemaValidator.pm. In .NET, Go, PHP, Python, Rust, Swift, and TypeScript the constants are defined and dead.That last point is the one I would fix first: seven SDKs publish an error code they can never emit, which is a stronger signal of intent than an absent feature would be.
Why it matters
The gap is easy to hit and silent. I annotated thirty-seven enums across a sample corpus and had to write a separate checker script to find the mistakes I made while doing it — wrong symbol keys, a missing entry, an empty label. The SDK reported every one of those schemas as valid.
Proposal
Implement schema-time validation for the Alternate Names keywords, in the shared rule set so that all languages get it:
altnames— object; every value a non-empty string. (Port the Java implementation.)descriptions— object; every value a non-empty string.altenums— object; every value an object; every value of that inner object a non-empty string; the enclosing schema has anenum; the inner object's keys are enum values.The last two of those depend on questions the Alternate Names draft does not currently answer — how a non-string enum value is written as a mapping key, and whether a mapping may be partial. I have opened those separately against
json-structure/alternate-names; the key-form check should follow whatever is decided there. The first three checks do not depend on anything and could land now.Whatever lands, please add the negative cases to
test-assets/so the implementations converge rather than each inventing a subset.