diff --git a/src/v3/types.ts b/src/v3/types.ts --- a/src/v3/types.ts +++ b/src/v3/types.ts @@ -2263,6 +2263,7 @@ exact: true, message: def.exactLength.message, }); + if (tooBig) return INVALID; status.dirty(); } } @@ -2291,7 +2292,7 @@ exact: false, message: def.maxLength.message, }); - status.dirty(); + return INVALID; } } @@ -3723,7 +3724,7 @@ exact: false, message: def.maxSize.message, }); - status.dirty(); + return INVALID; } } diff --git a/v3/types.js b/v3/types.js --- a/v3/types.js +++ b/v3/types.js @@ -1769,6 +1769,7 @@ exact: true, message: def.exactLength.message, }); + if (tooBig) return INVALID; status.dirty(); } } @@ -1795,7 +1796,7 @@ exact: false, message: def.maxLength.message, }); - status.dirty(); + return INVALID; } } if (ctx.common.async) { @@ -2814,7 +2815,7 @@ exact: false, message: def.maxSize.message, }); - status.dirty(); + return INVALID; } } const valueType = this._def.valueType; diff --git a/v3/types.cjs b/v3/types.cjs --- a/v3/types.cjs +++ b/v3/types.cjs @@ -1790,6 +1790,7 @@ exact: true, message: def.exactLength.message, }); + if (tooBig) return parseUtil_js_1.INVALID; status.dirty(); } } @@ -1816,7 +1817,7 @@ exact: false, message: def.maxLength.message, }); - status.dirty(); + return parseUtil_js_1.INVALID; } } if (ctx.common.async) { @@ -2843,7 +2844,7 @@ exact: false, message: def.maxSize.message, }); - status.dirty(); + return parseUtil_js_1.INVALID; } } const valueType = this._def.valueType; diff --git a/src/v4/core/schemas.ts b/src/v4/core/schemas.ts --- a/src/v4/core/schemas.ts +++ b/src/v4/core/schemas.ts @@ -242,6 +242,26 @@ }; inst._zod.run = (payload, ctx) => { + const value = payload.value; + const size = def.type === "array" && Array.isArray(value) ? value.length + : (def.type === "map" && value instanceof Map) || (def.type === "set" && value instanceof Set) ? value.size : -1; + if (size >= 0) { + for (const ch of checks) { + const checkDef = ch._zod.def; + if (!["min_length", "max_length", "length_equals", "min_size", "max_size", "size_equals"].includes(checkDef.check)) break; + const maximum = "maximum" in checkDef ? checkDef.maximum + : "length" in checkDef ? checkDef.length : "size" in checkDef ? checkDef.size : undefined; + if (typeof maximum === "number" && size > maximum && (!checkDef.when || checkDef.when(payload))) { + const start = payload.issues.length; + // SAFETY: Built-in size checks run only after the matching collection type guard. + ch._zod.check(payload as ParsePayload); + for (let i = start; i < payload.issues.length; i++) { + payload.issues[i] = { ...payload.issues[i], continue: false }; + } + return payload; + } + } + } const result = inst._zod.parse(payload, ctx); if (result instanceof Promise) { diff --git a/v4/core/schemas.js b/v4/core/schemas.js --- a/v4/core/schemas.js +++ b/v4/core/schemas.js @@ -74,6 +74,25 @@ return payload; }; inst._zod.run = (payload, ctx) => { + const value = payload.value; + const size = def.type === "array" && Array.isArray(value) ? value.length + : (def.type === "map" && value instanceof Map) || (def.type === "set" && value instanceof Set) ? value.size : -1; + if (size >= 0) { + for (const ch of checks) { + const checkDef = ch._zod.def; + if (!["min_length", "max_length", "length_equals", "min_size", "max_size", "size_equals"].includes(checkDef.check)) break; + const maximum = "maximum" in checkDef ? checkDef.maximum + : "length" in checkDef ? checkDef.length : "size" in checkDef ? checkDef.size : undefined; + if (typeof maximum === "number" && size > maximum && (!checkDef.when || checkDef.when(payload))) { + const start = payload.issues.length; + ch._zod.check(payload); + for (let i = start; i < payload.issues.length; i++) { + payload.issues[i] = { ...payload.issues[i], continue: false }; + } + return payload; + } + } + } const result = inst._zod.parse(payload, ctx); if (result instanceof Promise) { if (ctx.async === false) diff --git a/v4/core/schemas.cjs b/v4/core/schemas.cjs --- a/v4/core/schemas.cjs +++ b/v4/core/schemas.cjs @@ -104,6 +104,25 @@ return payload; }; inst._zod.run = (payload, ctx) => { + const value = payload.value; + const size = def.type === "array" && Array.isArray(value) ? value.length + : (def.type === "map" && value instanceof Map) || (def.type === "set" && value instanceof Set) ? value.size : -1; + if (size >= 0) { + for (const ch of checks) { + const checkDef = ch._zod.def; + if (!["min_length", "max_length", "length_equals", "min_size", "max_size", "size_equals"].includes(checkDef.check)) break; + const maximum = "maximum" in checkDef ? checkDef.maximum + : "length" in checkDef ? checkDef.length : "size" in checkDef ? checkDef.size : undefined; + if (typeof maximum === "number" && size > maximum && (!checkDef.when || checkDef.when(payload))) { + const start = payload.issues.length; + ch._zod.check(payload); + for (let i = start; i < payload.issues.length; i++) { + payload.issues[i] = { ...payload.issues[i], continue: false }; + } + return payload; + } + } + } const result = inst._zod.parse(payload, ctx); if (result instanceof Promise) { if (ctx.async === false)