From 167541a4d7c2ec7b21b23532bcabc1fb69a1ec5d Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 24 Oct 2026 13:57:51 +0000 Subject: [PATCH] fix(downgrader): clear the 3.1 to 3.0 nullable-merge lists when conversion 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) Claude-Session: https://claude.ai/code/session_01NerLPPYvjVTGwnV3s1in2V --- packages/downgrader/src/v3.1-to-v3.0.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/downgrader/src/v3.1-to-v3.0.ts b/packages/downgrader/src/v3.1-to-v3.0.ts index 0b8ff35..b0cfff0 100644 --- a/packages/downgrader/src/v3.1-to-v3.0.ts +++ b/packages/downgrader/src/v3.1-to-v3.0.ts @@ -794,16 +794,19 @@ function convertDocument(value: unknown, ctx: Context): unknown { } function downgradeV30(root: unknown, convert: Convert): unknown { - twoBranchAnyOfs.length = 0 - anyOfTargets.clear() - const out = downgrade(root, convert) - for (const [schema, input] of twoBranchAnyOfs.splice(0)) { - if (!anyOfTargets.has(input)) { - mergeNullable(schema, root) + try { + const out = downgrade(root, convert) + for (const [schema, input] of twoBranchAnyOfs) { + if (!anyOfTargets.has(input)) { + mergeNullable(schema, root) + } } + return out + } finally { + // Cleared even when conversion throws, so nothing keeps the input alive. + twoBranchAnyOfs.length = 0 + anyOfTargets.clear() } - anyOfTargets.clear() - return out } export function downgradeSpecV31ToV30(spec: OpenAPIV3_1.OpenAPIObject): OpenAPIV3_0.OpenAPIObject {