Repository navigation
fix: never fall back to an unescaped CFG for JSON string patterns - #986
mahmoudhas wants to merge 1 commit into
Conversation
|
One known remaining edge for reviewer awareness (non-blocking for us): this patch removes the unescaped-CFG fallback for JSON-string patterns, but the |
There was a problem hiding this comment.
🟡 Changes recommended
Large-repeat helpers still bypass JSON exclusions, and existing Python tests retain incompatible expectations.
2 open findings
What changed in this PR
This PR hardens JSON Schema string-pattern conversion by removing the unescaped regex fallback while preserving raw regex behavior.
Changes:
- Routes Unicode patterns through the JSON-safe FSM.
- Rejects unsupported or empty JSON-safe pattern languages.
- Adds C++ coverage for Unicode, forbidden characters, and escaped-only patterns.
| File | Description |
|---|---|
| tests/cpp/test_json.cc | Adds pattern-safety and raw-regex regression tests. |
| cpp/json_schema_converter.cc | Enables Unicode FSM conversion and blocks unsafe JSON-string fallback. |
🧠 Review effort: Balanced
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if (!force_cfg_expansion) { | ||
| auto fsm_result = GrammarFSMBuilder::Regex(regex, json_string); |
| XGRAMMAR_CHECK(!json_string) | ||
| << "JSON string pattern has no JSON-safe canonical representation or uses unsupported regex " | ||
| "syntax; patterns requiring escaped quotes, backslashes or control characters are not " | ||
| "supported"; |


Problem
JSONSchemaConverter::RegexExpressionfalls back to a raw regex CFG when the JSON-safe FSM is unavailable/empty, and unconditionally routes non-ASCII/control-containing patterns to that fallback. The surrounding string quotes are then added without JSON escaping.Minimal examples that the current grammar accepts as complete:
{"type":"string","pattern":"^\"$"}accepts raw""".{"type":"string","pattern":"^[é\\s\\S]{1,64}$"}accepts"hello"world"and raw control bytes.These are syntactically invalid JSON, regardless of independent schema validation.
Change
json_string=true.This does not implement arbitrary escaped spellings or change the other existing regex semantics. Independent output validation should remain enabled.
Tests
75/75 C++ tests passed, including new tests covering Unicode/BMP/astral literals, wildcard patterns, all 32 C0 control bytes, quote exclusion, nested schemas, and pre-generation rejection of escaped-only patterns. Raw regex literal-quote matching remains supported.
Built against the native revision bundled in Rust xgrammar 0.5.1 (
82505d0), with clang 18 on Linux aarch64. The relevant converter implementation still has the same fallback on current main.