Skip to content

fix: apply strictNumbers when coercing strings to numbers - #2661

Open
amantu-qbit wants to merge 1 commit into
ajv-validator:masterfrom
amantu-qbit:fix/coercion-respects-strict-numbers
Open

fix: apply strictNumbers when coercing strings to numbers#2661
amantu-qbit wants to merge 1 commit into
ajv-validator:masterfrom
amantu-qbit:fix/coercion-respects-strict-numbers

Conversation

@amantu-qbit

Copy link
Copy Markdown

What

With coerceTypes enabled, the string "Infinity" validates as both number and integer under the default strictNumbers: true.

coerceData assigns the result of +data without repeating the finiteness check that checkDataType applies, so strictNumbers is only enforced on the branch for values that are already numbers.

For integer the value also slips past the fractional-part test, because Infinity % 1 is NaN and !(NaN) is true.

"NaN" was rejected only incidentally — data == +data is false for it — which is why the two behave differently today.

The same applies to any string that overflows, so 1e999 is accepted as an integer and reaches the caller as a non-finite number. That's the realistic trigger: it's an ordinary-looking number to a client.

How

Gate the string coercion on isFinite when strictNumbers is set, matching checkDataType. With strictNumbers: false, previous behaviour is unchanged.

Tests

Three cases in spec/coercion.spec.ts: non-finite strings rejected by default for both number and integer, finite strings (including 1e300) still coercing, and strictNumbers: false still coercing to Infinity. Full suite: 7615 passing, 0 failing.

Context

This was traced from fastify/fastify#6718, where ?num=Infinity and ?num=1e999 pass type: integer validation and reach the handler as non-finite numbers. The Fastify maintainers closed that issue as belonging here.

Type coercion assigned the result of `+data` without repeating the finiteness
check that `checkDataType` applies, so with `coerceTypes` enabled the string
"Infinity" validated as both `number` and `integer` even under the default
`strictNumbers: true`.

For `integer` the value also slipped past the fractional-part test, because
`Infinity % 1` is NaN and `!(NaN)` is true. "NaN" was rejected only incidentally,
by `data == +data` being false, which is why the two behaved differently.

The same applies to any string that overflows to Infinity, so `1e999` was
accepted as an integer and reached the caller as a non-finite number.

Gate the coercion on `isFinite` when `strictNumbers` is set, matching what
`checkDataType` already does for values that arrive as numbers. With
`strictNumbers: false` the previous behaviour is unchanged.
Copilot AI lite review requested due to automatic review settings August 10, 2026 05:13

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants