Skip to content

fix: numeric validator accepts '123abc', truncate exceeds maxLength - #306

Open
fix2015 wants to merge 1 commit into
vercel-labs:mainfrom
fix2015:fix/numeric-validator-and-truncate-length
Open

fix: numeric validator accepts '123abc', truncate exceeds maxLength#306
fix2015 wants to merge 1 commit into
vercel-labs:mainfrom
fix2015:fix/numeric-validator-and-truncate-length

Conversation

@fix2015

@fix2015 fix2015 commented Jul 6, 2026

Copy link
Copy Markdown

Two bugs:

  • the `numeric` validator was using `parseFloat` which parses `"123abc"` as `123` and passes validation. Users could submit `"99bottles"` and it would be accepted as a valid number. Changed to `Number()` which correctly returns `NaN` for strings with trailing non-numeric characters.

  • the `$truncate` directive was producing strings longer than `maxLength` because it did `text.slice(0, maxLength) + suffix` without accounting for the suffix length. So `length: 50` with a `"..."` suffix would produce a 53-character string. Changed to `text.slice(0, maxLength - suffix.length)` so the final output actually respects the limit.

- the numeric validation used parseFloat which parses "123abc" as 123
  and passes validation. changed to Number() which correctly returns
  NaN for strings with trailing non-numeric characters.
- truncate directive produced strings longer than maxLength because
  the suffix length wasn't subtracted from the slice. "hello world"
  truncated to length 8 with "..." suffix became 11 chars instead of 8.
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

@fix2015 is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

numeric: (value: unknown) => {
if (typeof value === "number") return !isNaN(value);
if (typeof value === "string") return !isNaN(parseFloat(value));
if (typeof value === "string") return !isNaN(Number(value)) && isFinite(Number(value));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (typeof value === "string") return !isNaN(Number(value)) && isFinite(Number(value));
if (typeof value === "string") {
const trimmed = value.trim();
if (trimmed === "") return false;
return !isNaN(Number(trimmed)) && isFinite(Number(trimmed));
}

The numeric validator accepts empty and whitespace-only strings as valid numbers because Number("") and Number(" ") both evaluate to a finite 0.

Fix on Vercel


if (text.length <= maxLength) return text;
return text.slice(0, maxLength) + suffix;
return text.slice(0, maxLength - suffix.length) + suffix;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$truncate uses text.slice(0, maxLength - suffix.length) without clamping the start index, so a suffix longer than maxLength yields a negative index that slices from the end and returns nearly the whole string; the same change also broke 3 existing tests that encoded the old contract.

Fix on Vercel

@dofaromg

dofaromg commented Jul 7, 2026

Copy link
Copy Markdown

@claude

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants