You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Runaway recursion on 3.13 and higher for _PY_FRAME_GENERAL #132744
I'm hesitant to backport the fix to 3.13, as it might break existing code.
3.13.8 commit ebccd1de88d indeed broke ruamel in a hyper-specific test case (only with pytest-xdist) and in a totally inexplicable way.
In that specific test configuration, a default integer function parameter becomes a ruamel.yaml.reader.Reader object!!?! Hilarity ensues. This makes absolutely no sense.
While the specific test configuration that reproduces requires a bit of a setup effort, once it's set up then git bisect is 100% deterministic and lands exactly on ebccd1de88d. 0% repro without that commit, 100% repro with it.
You should up the sys recursion limit for that test.
Interesting suggestion, thanks. I tried sys.setrecursionlimit(100) and sys.setrecursionlimit(10000) and they only make things faster or slower but they cause absolutely no functional change whatsoever. All the failing configurations still fail and all the passing configurations still pass.
anything that this breaks should be buggy.
So I bisected ruamel and the git bisect unambiguously landed on some 0.16.3 commit that merely moves some yaml_version field from one class to another which I can't possibly relate to anything that is happening...
To make sure, I reverted that ruamel 0.16.3 commit on top of the latest 0.18.6 release, solved a few minor conflicts and that revert does make the test pass again!!
This is crazy, I've never seen anything like it. This type of elusive bug usually involves non-determinism but not in this case! In this case git bisects are never ambiguous and all configurations that fail, fail exactly the same.
Interesting suggestion, thanks. I tried sys.setrecursionlimit(100) and sys.setrecursionlimit(10000) and they only make things faster or slower but they cause absolutely no functional change whatsoever. All the failing configurations still fail and all the passing configurations still pass.
Data point from production (Windows 11, CPython 3.13.5): a test double declared as def fake(path, **kw) that recursed into itself never raised RecursionError
(sys.getrecursionlimit() == 1000). It reached a depth of 5.27 million frames in 2.4 s
while allocating ~400-800 MB/s, and exhausted 128 GB of RAM plus the page file three
times in one day (two resource-exhaustion shutdowns and one 0xEF bugcheck).
The same function without **kw raises RecursionError at depth 998 as expected, so the _PY_FRAME_GENERAL path is the trigger here too (not only default arguments).
Minimal reproduction:
n=0deff(path, **kw):
globalnn+=1ifn>=200_000:
returnreturnf(path)
f("x") # returns after 200,000 frames on 3.13.5; RecursionError expected
Hoping this helps prioritize the 3.13 backport (gh-138032). Thank you.
Hoping this helps prioritize the 3.13 backport (#138032). Thank you.
This backport was merged more than 1 year ago and released in 3.13.8...
Note it also had a 3.13-specific regression, see above and in the summary I just posted in 138032.
That regression was fixed by PR #145015 merged 6+ months ago and released in 3.13.13
Data point from production (Windows 11, CPython 3.13.5)
Activity
gh-132744: Check recursion limit in CALL_PY_GENERAL (GH-132746)
brandtbucher commentedon May 6, 2025
Can this be closed? I think we still need the manual backport.
Fidget-Spinner commentedon May 6, 2025
I think Mark intends to backport it but I'm ambivalent
brandtbucher commentedon May 6, 2025
@markshannon, looks like this needs a manual backport.
pythongh-132744: Check recursion limit in CALL_PY_GENERAL (pythonGH-1…
Fidget-Spinner commentedon Aug 19, 2025
I marked this easy to welcome contributors to backport this to 3.13. You don't need to implement anything new, please instead see the already merged PR and follow the backport procedure here https://devguide.python.org/contrib/core-team/committing/#backporting-changes-to-an-older-version. the backport has to be manual.
skv0zsneg commentedon Aug 19, 2025
Hello everyone! Can I work on this issue?
Fidget-Spinner commentedon Aug 19, 2025
@skv0zsneg yes please.
Fidget-Spinner commentedon Aug 19, 2025
For anyone wanting to contribute. These are the steps:
make regen-caseson Linux orbuild.bat --regenon Windows.[3.13] gh-132744: Check recursion limit in _PY_FRAME_GENERAL (GH-132746…
marc-hb commentedon Feb 12, 2026
3.13.8 commit ebccd1de88d indeed broke
ruamelin a hyper-specific test case (only with pytest-xdist) and in a totally inexplicable way.In that specific test configuration, a default integer function parameter becomes a
ruamel.yaml.reader.Readerobject!!?! Hilarity ensues. This makes absolutely no sense.While the specific test configuration that reproduces requires a bit of a setup effort, once it's set up then
git bisectis 100% deterministic and lands exactly on ebccd1de88d. 0% repro without that commit, 100% repro with it.See zephyrproject-rtos/west#908 (comment) for complete details.
Fidget-Spinner commentedon Feb 12, 2026
@marc-hb anything that this breaks should be buggy. You should up the sys recursion limit for that test.
marc-hb commentedon Feb 13, 2026
Interesting suggestion, thanks. I tried
sys.setrecursionlimit(100)andsys.setrecursionlimit(10000)and they only make things faster or slower but they cause absolutely no functional change whatsoever. All the failing configurations still fail and all the passing configurations still pass.So I bisected
ruameland the git bisect unambiguously landed on some 0.16.3 commit that merely moves someyaml_versionfield from one class to another which I can't possibly relate to anything that is happening...To make sure, I reverted that ruamel 0.16.3 commit on top of the latest 0.18.6 release, solved a few minor conflicts and that revert does make the test pass again!!
marc-hb/ruamel-yaml@88a38c7
This is crazy, I've never seen anything like it. This type of elusive bug usually involves non-determinism but not in this case! In this case git bisects are never ambiguous and all configurations that fail, fail exactly the same.
Any idea?
marc-hb commentedon Feb 13, 2026
I think I just got a breakthrough and I need to take that back. Apologies for using this issue for https://en.wikipedia.org/wiki/Rubber_duck_debugging
Instead of making "exponential" variations, I just tried these tiny ones (all other things being equal)
So now I suspect some subtle
try/catchbug in ruamel is being triggered by this change.I can see this happening with other libraries!
marc-hb commentedon Feb 19, 2026
Link to tentative fix just for the record:
xxGodLiuxx commentedon Sep 16, 2026
Data point from production (Windows 11, CPython 3.13.5): a test double declared as
def fake(path, **kw)that recursed into itself never raised RecursionError(
sys.getrecursionlimit() == 1000). It reached a depth of 5.27 million frames in 2.4 swhile allocating ~400-800 MB/s, and exhausted 128 GB of RAM plus the page file three
times in one day (two resource-exhaustion shutdowns and one 0xEF bugcheck).
The same function without
**kwraises RecursionError at depth 998 as expected, so the_PY_FRAME_GENERALpath is the trigger here too (not only default arguments).Minimal reproduction:
Hoping this helps prioritize the 3.13 backport (gh-138032). Thank you.
marc-hb commentedon Sep 16, 2026
This backport was merged more than 1 year ago and released in 3.13.8...
Note it also had a 3.13-specific regression, see above and in the summary I just posted in 138032.
That regression was fixed by PR #145015 merged 6+ months ago and released in 3.13.13
3.13.5 ??