Repository navigation
Conversation
…rsion throws downgradeV30 keeps two module-level lists, twoBranchAnyOfs and anyOfTargets, that were only cleared on success. A throw (such as the RangeError on very deep nesting) left them holding the input and partial output until the next call. Wrap the body in try/finally and clear them once there. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NerLPPYvjVTGwnV3s1in2V
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes
- Wrap
downgradeV30intry/finally— clearstwoBranchAnyOfsandanyOfTargetseven when conversion throws, so a failed call no longer retains the input and partial output until the next call. - Drop the start-of-call clear — now redundant since every call ends with both lists empty.
- Iterate
twoBranchAnyOfsdirectly instead ofsplice(0)— valid becausemergeNullablenever pushes to the list.
The direct iteration is safe: mergeNullable only calls isOnlyNullSchema, isRecord, getRef, find, rejectsNull, and Object.assign, none of which re-enter conversion. downgradeV30 is also not re-entrant — the chained 3.2→3.1→3.0 path calls the two downgraders sequentially — so removing the defensive start-of-call clear cannot leak state between calls.
I confirmed the fix empirically with a throwaway probe (200k two-branch-anyOf schemas plus a >1000-deep schema to force the documented RangeError): the base retains ~142 MB after the throw, while this branch retains ~0 MB. A successful call retains ~0 MB on both. pnpm test passes (262 tests).
deepseek-v4.1-flash (free via Pullfrog for OSS) | 𝕏

Requested by dinwwwh · project thread
Problem
downgradeV30insrc/v3.1-to-v3.0.tskeeps two module-level lists,twoBranchAnyOfsandanyOfTargets, for the nullable merge. They were cleared at the start of a call and at its successful end, but not when conversion threw (for example theRangeErroron very deep nesting that the README lists). Until the next call, they kept the input and the partial output alive: on a 50k-schema doc, about 61.7 MB stayed retained after a throw versus 4.2 MB after a success.Fix
Wrap the body in
try/finallyand clear both lists once, infinally. Since every call now ends with them empty, the clear at the start is dropped. The loop iteratestwoBranchAnyOfsdirectly instead ofsplice(0), becausemergeNullablenever pushes to it.Checks
pnpm test: 262 tests pass;pnpm run checkclean.mainon 80 real 3.1 documents.RangeErrorstill mergesanyOf: [string, null]intonullable: true. No gc-based unit test, since that would be flaky.Generated by Claude Code