When a $defs array definition references itself (directly or through a chain of only-array definitions), weaseljson_schemagen.py creates a self-referential TArr and then recurses infinitely while rendering C++ types.
In contrib/schemagen/weaseljson_schemagen.py lines 311-326, build_type for arrays registers the new TArr in self._buildingbefore building its items. When the items contain a $ref back to the same definition, build_def returns the cached tuple (t, nullable), so the assignment t.elem = elem makes the array its own element type.
This self-reference then causes infinite recursion in multiple places:
base_cpp (lines 473-486) and storage_cpp (lines 489-494) recurse on ty.elem.
_walk_arrays (lines 568-573) recurses on ty.elem.
Object-only cycles are handled by break_cycles using std::unique_ptr, but array-only cycles have no object edge for break_cycles to cut.
Expected behavior
Either:
Generate a valid C++ type for recursive arrays (e.g., std::vector<std::unique_ptr<...>>), or
Reject the schema at generation time with a clear GenError instead of crashing.
Actual behavior
Python stack overflow / RecursionError.
Impact
Any schema that models a recursive tree of arrays (e.g., nested lists, s-expressions, filesystem-like trees where every node is an array of nodes) will crash the generator. A crashing generator is also problematic for CI pipelines or web services that accept user-supplied schemas.
When a `$defs` array definition references itself (directly or through a chain of only-array definitions), `weaseljson_schemagen.py` creates a self-referential `TArr` and then recurses infinitely while rendering C++ types.
**Reproduction**
```json
{
"type": "array",
"items": { "$ref": "#/$defs/Node" },
"$defs": {
"Node": {
"type": "array",
"items": { "$ref": "#/$defs/Node" }
}
}
}
```
Run:
```sh
python3 contrib/schemagen/weaseljson_schemagen.py schema.json -o gen.h --namespace ns
```
Result:
```
RecursionError: maximum recursion depth exceeded
```
The same crash happens for an object field that points to a self-referential array:
```json
{
"type": "object",
"properties": {
"items": { "$ref": "#/$defs/Items" }
},
"$defs": {
"Items": {
"type": "array",
"items": { "$ref": "#/$defs/Items" }
}
}
}
```
**Root cause**
In `contrib/schemagen/weaseljson_schemagen.py` lines 311-326, `build_type` for arrays registers the new `TArr` in `self._building` *before* building its `items`. When the items contain a `$ref` back to the same definition, `build_def` returns the cached tuple `(t, nullable)`, so the assignment `t.elem = elem` makes the array its own element type.
This self-reference then causes infinite recursion in multiple places:
- `base_cpp` (lines 473-486) and `storage_cpp` (lines 489-494) recurse on `ty.elem`.
- `_walk_arrays` (lines 568-573) recurses on `ty.elem`.
Object-only cycles are handled by `break_cycles` using `std::unique_ptr`, but array-only cycles have no object edge for `break_cycles` to cut.
**Expected behavior**
Either:
1. Generate a valid C++ type for recursive arrays (e.g., `std::vector<std::unique_ptr<...>>`), or
2. Reject the schema at generation time with a clear `GenError` instead of crashing.
**Actual behavior**
Python stack overflow / `RecursionError`.
**Impact**
Any schema that models a recursive tree of arrays (e.g., nested lists, s-expressions, filesystem-like trees where every node is an array of nodes) will crash the generator. A crashing generator is also problematic for CI pipelines or web services that accept user-supplied schemas.
weaselbot
was assigned by andrew2026-06-30 16:19:15 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
When a
$defsarray definition references itself (directly or through a chain of only-array definitions),weaseljson_schemagen.pycreates a self-referentialTArrand then recurses infinitely while rendering C++ types.Reproduction
Run:
Result:
The same crash happens for an object field that points to a self-referential array:
Root cause
In
contrib/schemagen/weaseljson_schemagen.pylines 311-326,build_typefor arrays registers the newTArrinself._buildingbefore building itsitems. When the items contain a$refback to the same definition,build_defreturns the cached tuple(t, nullable), so the assignmentt.elem = elemmakes the array its own element type.This self-reference then causes infinite recursion in multiple places:
base_cpp(lines 473-486) andstorage_cpp(lines 489-494) recurse onty.elem._walk_arrays(lines 568-573) recurses onty.elem.Object-only cycles are handled by
break_cyclesusingstd::unique_ptr, but array-only cycles have no object edge forbreak_cyclesto cut.Expected behavior
Either:
std::vector<std::unique_ptr<...>>), orGenErrorinstead of crashing.Actual behavior
Python stack overflow /
RecursionError.Impact
Any schema that models a recursive tree of arrays (e.g., nested lists, s-expressions, filesystem-like trees where every node is an array of nodes) will crash the generator. A crashing generator is also problematic for CI pipelines or web services that accept user-supplied schemas.