From dd492901d19f70aec69ad9c6a86b94f51434de5e Mon Sep 17 00:00:00 2001 From: Shreya Sharma Date: Thu, 8 Jan 2026 23:20:35 +0530 Subject: [PATCH 1/3] fixes --- src/core/friendly_errors/param_validator.js | 82 +++++++++++++-------- 1 file changed, 53 insertions(+), 29 deletions(-) diff --git a/src/core/friendly_errors/param_validator.js b/src/core/friendly_errors/param_validator.js index 790b470168..6ca8fc4362 100644 --- a/src/core/friendly_errors/param_validator.js +++ b/src/core/friendly_errors/param_validator.js @@ -64,7 +64,7 @@ function validateParams(p5, fn, lifecycles) { 'Boolean': z.boolean(), 'Function': z.function(), 'Integer': z.number().int(), - 'Number': z.number(), + 'Number': z.union([z.number(), z.literal(Infinity), z.literal(-Infinity)]), 'Object': z.object({}), 'String': z.string() }; @@ -415,46 +415,70 @@ function validateParams(p5, fn, lifecycles) { const expectedTypes = new Set(); let actualType; - error.errors.forEach(err => { - const issue = err[0]; - if (issue) { + let sawNumber = false; + let sawInfinityLiteral = false; + let sawNonInfinityConstant = false; + + const flattenIssues = iss => { + if (!iss) return []; + if (iss.code === 'invalid_union') { + const subs = iss.unionErrors?.flatMap(u => u.issues) || []; + return subs.flatMap(si => flattenIssues(si[0] || si)); + } + return [iss]; + }; + + const flat = (error.errors || []).flatMap(e => flattenIssues(e[0])); + + for (const issue of flat) { + if (!issue) continue; + + if (issue.code === 'invalid_type') { + if (issue.expected === 'number') sawNumber = true; if (!actualType) { - actualType = issue.message; + const rec = issue.message?.split(', received ')[1]; + if (rec) actualType = rec; } + continue; + } - if (issue.code === 'invalid_type') { - actualType = issue.message.split(', received ')[1]; - expectedTypes.add(issue.expected); - } - // The case for constants. Since we don't want to print out the actual - // constant values in the error message, the error message will - // direct users to the documentation. - else if (issue.code === 'invalid_value') { - expectedTypes.add('constant (please refer to documentation for allowed values)'); - actualType = args[error.path[0]]; - } else if (issue.code === 'custom') { - const match = issue.message.match(/Input not instance of (\w+)/); - if (match) expectedTypes.add(match[1]); - actualType = undefined; + if (issue.code === 'invalid_literal' || issue.code === 'invalid_value') { + const exp = 'expected' in issue ? issue.expected : undefined; + if (exp === Infinity || exp === -Infinity) { + sawInfinityLiteral = true; + } else { + sawNonInfinityConstant = true; } + if (!actualType) actualType = args[error.path[0]]; + continue; } - }); + + if (issue.code === 'custom') { + const m = issue.message?.match(/Input not instance of (\w+)/); + if (m) expectedTypes.add(m[1]); + actualType = undefined; + continue; + } + } + + if (sawNumber) expectedTypes.add('number'); + if (sawNonInfinityConstant) { + expectedTypes.add('constant (please refer to documentation for allowed values)'); + } + + if (sawNumber && sawInfinityLiteral && !sawNonInfinityConstant) { + expectedTypes.delete('constant (please refer to documentation for allowed values)'); + } if (expectedTypes.size > 0) { - if (error.path?.length > 0 && args[error.path[0]] instanceof Promise) { - message += 'Did you mean to put `await` before a loading function? ' + - 'An unexpected Promise was found. '; + if (error.path?.length > 0 && args[error.path[0]] instanceof Promise) { + message += 'Did you mean to put `await` before a loading function? An unexpected Promise was found. '; isVersionError = true; } - const expectedTypesStr = Array.from(expectedTypes).join(' or '); const position = error.path.join('.'); - - message += buildTypeMismatchMessage( - actualType, expectedTypesStr, position - ); + message += buildTypeMismatchMessage(actualType, expectedTypesStr, position); } - return message; }; From cf1f8c3366aa21c7d21c6fc00f6a3f4cf6c0ccd6 Mon Sep 17 00:00:00 2001 From: Perminder Singh <127239756+perminder-17@users.noreply.github.com> Date: Sun, 11 Jan 2026 20:57:03 +0530 Subject: [PATCH 2/3] Refactor error flattening and type detection --- src/core/friendly_errors/param_validator.js | 34 ++++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/core/friendly_errors/param_validator.js b/src/core/friendly_errors/param_validator.js index 6ca8fc4362..6075b17fff 100644 --- a/src/core/friendly_errors/param_validator.js +++ b/src/core/friendly_errors/param_validator.js @@ -428,13 +428,23 @@ function validateParams(p5, fn, lifecycles) { return [iss]; }; - const flat = (error.errors || []).flatMap(e => flattenIssues(e[0])); + const flat = (error.errors || []).flatMap(e => + (Array.isArray(e) ? e : [e]).flatMap(i => flattenIssues(i)) + ); + + const typeOfArg = val => { + if (val === null) return 'null'; + if (Array.isArray(val)) return 'array'; + if (typeof val === 'number' && Number.isNaN(val)) return 'NaN'; + return typeof val; + }; for (const issue of flat) { if (!issue) continue; if (issue.code === 'invalid_type') { if (issue.expected === 'number') sawNumber = true; + if (issue.expected) expectedTypes.add(issue.expected); if (!actualType) { const rec = issue.message?.split(', received ')[1]; if (rec) actualType = rec; @@ -443,13 +453,21 @@ function validateParams(p5, fn, lifecycles) { } if (issue.code === 'invalid_literal' || issue.code === 'invalid_value') { - const exp = 'expected' in issue ? issue.expected : undefined; - if (exp === Infinity || exp === -Infinity) { - sawInfinityLiteral = true; - } else { - sawNonInfinityConstant = true; - } - if (!actualType) actualType = args[error.path[0]]; + const values = Array.isArray(issue.values) + ? issue.values + : ('expected' in issue ? [issue.expected] : []); + + if (values.some(v => v === Infinity || v === -Infinity)) { + sawInfinityLiteral = true; + } + + if (values.some(v => v !== Infinity && v !== -Infinity)) { + sawNonInfinityConstant = true; + } + + const idx = issue.path?.[0] ?? error.path?.[0]; + if (!actualType && idx !== undefined) actualType = typeOfArg(args[idx]); + continue; } From 0f5a475d45e99ed048a29366972a572a610f029f Mon Sep 17 00:00:00 2001 From: Perminder Singh <127239756+perminder-17@users.noreply.github.com> Date: Mon, 12 Jan 2026 00:26:58 +0530 Subject: [PATCH 3/3] Adding more conditions for fixing --- src/core/friendly_errors/param_validator.js | 23 +++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/core/friendly_errors/param_validator.js b/src/core/friendly_errors/param_validator.js index 6075b17fff..1e77ec88db 100644 --- a/src/core/friendly_errors/param_validator.js +++ b/src/core/friendly_errors/param_validator.js @@ -422,8 +422,15 @@ function validateParams(p5, fn, lifecycles) { const flattenIssues = iss => { if (!iss) return []; if (iss.code === 'invalid_union') { - const subs = iss.unionErrors?.flatMap(u => u.issues) || []; - return subs.flatMap(si => flattenIssues(si[0] || si)); + const subsV3 = iss.unionErrors?.flatMap(u => u.issues) || []; + const subsV4 = iss.errors || []; + + const flatV3 = subsV3.flatMap(si => flattenIssues(si[0] || si)); + const flatV4 = subsV4.flatMap(e => + (Array.isArray(e) ? e : [e]).flatMap(i => flattenIssues(i)) + ); + + return [...flatV3, ...flatV4]; } return [iss]; }; @@ -493,9 +500,17 @@ function validateParams(p5, fn, lifecycles) { message += 'Did you mean to put `await` before a loading function? An unexpected Promise was found. '; isVersionError = true; } - const expectedTypesStr = Array.from(expectedTypes).join(' or '); + let expectedArr = Array.from(expectedTypes); + if (expectedTypes.has('number')) { + expectedArr = ['number', ...expectedArr.filter(t => t !== 'number')]; + } + const expectedTypesStr = expectedArr.join(' or '); + const position = error.path.join('.'); - message += buildTypeMismatchMessage(actualType, expectedTypesStr, position); + const idx = error.path?.[0]; + const received = + sawNonInfinityConstant && idx !== undefined ? args[idx] : actualType; + message += buildTypeMismatchMessage(received, expectedTypesStr, position); } return message; };