Repository navigation
Conversation
Java and Python compiled the per-target `$` end-anchor rewrite (`\z` / `\Z`) and also quoted that rewritten text in the `must match pattern` reason, so their messages diverged from Go and TypeScript. Keep the rewrite for matching only and quote the authored (loader-normalized) pattern in the reason, including `propertyNames` pattern violations. Python now emits the authored text as a plain string literal instead of reading `.pattern` off the compiled regex. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pattern.md's example reason is `must match pattern "^[a-z]+$", got "AB1"`, but only Go quoted the pattern (with `%q`); Java, Python and TypeScript printed it bare, Java also printed the offending value bare, and the `propertyNames` form differed per target: Java dropped the `invalid property name "k": ` prefix and TypeScript appended `, got …`. Define the exact form in pattern.md and propertyNames.md and emit it everywhere. The generator quotes the authored pattern once as a JSON string (`json_schema::pattern::violation_reason`) and each backend embeds those bytes; offending values and property-name keys are JSON-quoted at runtime by `JSON.stringify`, Python `_quote`, and new Go `quoteValue` / Java `Violation.quote` helpers, so text containing `"`, `\` or control characters renders identically. A `propertyNames` pattern failure reads `invalid property name "Bad": must match pattern "^[a-z]+$"`. Go's `propertyNames` pattern also no longer splices the pattern into a `fmt.Sprintf` format string, where a `%` would have been misread. tests/json_schema_violation_reasons.rs drives the same wire values through all four runtimes and asserts byte-identical reasons. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When a string fails a JSON Schema
pattern(or apropertyNameskey fails one), the four targets produced four different messages. Java and Python even quoted the pattern after the generator rewrote it for their regex engines ($→\z/\Z), so users saw a pattern they never wrote. This PR defines one exact wording inspecs/json-schema/features/pattern.mdand makes Go, Java, Python, and TypeScript produce byte-identical messages for the same input.Matching behavior is unchanged: only the human-readable
reasontext of violations changes. Violation paths, which values are accepted or rejected, and thePayloadValidationErrorshape are unaffected.Two commits, reviewable separately:
\z/\Zleak.User-visible changes
The new wording
patternon a valuemust match pattern "^[a-z]+$", got "AB1"patternon apropertyNameskeyinvalid property name "Bad": must match pattern "^[a-z]+$"Every quoted part (pattern, value, key) is a JSON string literal:
"and\are backslash-escaped,\b \f \n \r \tuse short escapes, other control characters become\u00xx, everything else is kept as-is. The quoted pattern is the authored one.Value
patternfailures — before → afterExample: pattern
^[a-z]+$, valueAB1.must match pattern "^[a-z]+$", got "AB1"\u0001instead of Go's\x01)must match pattern ^[a-z]+\z, got AB1must match pattern "^[a-z]+$", got "AB1"must match pattern ^[a-z]+\Z, got "AB1"must match pattern "^[a-z]+$", got "AB1"must match pattern ^[a-z]+$, got "AB1"must match pattern "^[a-z]+$", got "AB1"propertyNamespattern failures — before → afterExample: pattern
^[a-z]+$, keyBad.invalid property name "Bad": must match pattern ^[a-z]+$invalid property name "Bad": must match pattern "^[a-z]+$"must match pattern ^[a-z]+\z, got Badinvalid property name "Bad": must match pattern "^[a-z]+$"invalid property name "Bad": must match pattern ^[a-z]+\Zinvalid property name "Bad": must match pattern "^[a-z]+$"invalid property name "Bad": must match pattern ^[a-z]+$, got "Bad"invalid property name "Bad": must match pattern "^[a-z]+$"Other
propertyNamesfailures (length, enum, format)The
invalid property name <key>:prefix now JSON-quotes the key in every target. For ordinary keys nothing changes; for a key containing",\, or control characters:invalid property name "a"b": …); nowinvalid property name "a\"b": ….%q(Go escapes); now JSON escapes.Additional, minor bug fixes
got AB1), so an empty string or one with trailing spaces was invisible. Values are now quoted like every other target.propertyNamespattern failure had noinvalid property nameprefix, unlike every otherpropertyNamesfailure., got "<key>"topropertyNamespattern failures; the prefix already names the key.propertyNamespattern messages: the pattern was spliced into afmt.Sprintfformat string, so a%in a pattern was misread as a verb. Messages are now concatenated.pattern.mddocumented the TypeScript message incorrectly (it showed${PAT_RE}; the code embeds the pattern text).Implementation notes
src/json_schema/pattern.rsviolation_reason), and every generator embeds the same bytes; host-engine rewrites are still what's compiled for matching.JSON.stringify, Python's existing_quote, plus two small new runtime helpers — GoquoteValueand JavaViolation.quote(String)— which appear in every regenerated Go/Java runtime file.PRINCIPLES.mdP11 (reason text is informative, not compared across targets) gains an exception: a feature spec may define an exact reason form, aspattern.mdnow does.Reviewing the diff
44 files, but most are mechanical:
src/generator/json_schema/{go,java,python,typescript}.rs,src/json_schema/pattern.rs.features/pattern.md,features/propertyNames.md,PRINCIPLES.md;CHANGELOG.md(Unreleased → Fixed).tests/json_schema_violation_reasons.rsgenerates one schema into all four targets, runs it, and asserts identical(path, reason)lists — including a pattern containing"and\, a control-character value, and a quoted key. Plus updated assertions intests/generate_{java,python}.rsand each target's sample tests.samples/,advanced/samples/): only reason strings and the new Go/Java quoting helpers.Not in this PR
propertyNamesformat failures are still inconsistent (Java lacks the prefix; TypeScript appends, got). Same class of fix; left out to keep this PR topattern.Validation
cargo validateandcargo test --all-featurespass.🤖 Generated with Claude Code