Repository navigation
Fix Float truncation in integer coercion, also for array-form type - #214
Merged
Merged
Conversation
With coerce_value on, a single type: integer turns the Float 100000.0 into 100000. type: [integer, "null"] only tried coercion for Strings, so the same Float failed with a type mismatch. Rewriting nullable: true as a type array could change the validation result.
A single type sends nil to the nil validator before any type check. Without this, nil for a type array without null raised a type mismatch instead of NotNullError.
This already works, and the next change must keep it. The type array spec now uses eql, because eq also passes when 100000.0 stays a Float.
Integer() truncates a Float, so 1.5 became 1 and passed type: integer. coerce_value was written for Strings such as "5", and no spec covered a Float. A Float with no fractional part, such as 100000.0, is still converted.
Float::INFINITY and Float::NAN raised FloatDomainError instead of a ValidateError.
Array-form type now uses the integer coercion, so it follows the single type.
takayamaki
marked this pull request as ready for review
October 19, 2026 16:46
1 of 8 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
With
coerce_valueon,type: integercoerces a value withInteger(value).For a Float, this drops the fractional part.
So
1.5passestype: integerand becomes1.This bug has been there since
coerce_valuewas added in 7b4af75 (2018).I think the truncation was never intended.
The README shows coercion for Strings like
"1".No spec covers a Float with coercion.
committee turns
coerce_valueon for JSON request bodies by default.So committee passes a JSON body with
1.5for an integer field.I found this in a real app.
Some request specs sent a Float to an integer field and expected a 400.
They failed only after I rewrote
nullable: trueastype: [integer, "null"]for OpenAPI 3.1.This is because #212 made array-form
typecoerce only Strings.So the two forms gave different results for the same Float.
Changes
A Float with no fractional part, like
100000.0, still becomes100000.A Float with a fractional part, like
1.5, now fails.A non-finite Float now fails with
ValidateErrorinstead of raisingFloatDomainError.typenow coerces any non-nil value the same way as a single type, not only a String.Without this,
100000.0would still passtype: integerand failtype: [integer, "null"].nil still goes to the nil validator.
type: integerbeforetype: [integer, "null"]before"7"777100000.0100000ValidateError1000001.51ValidateErrorValidateErrorWith
coerce_valueoff, nothing changes.Behavior change
With
coerce_valueon, a request with1.5for an integer field passed before.It now fails.
This breaks anyone who relied on the truncation.
If you want to keep the truncation, I can drop that part and keep only the array-form change.
Notes
1and1.0are both integers:https://spec.openapis.org/oas/v3.1.1.html#data-types
With coercion, this PR matches that.
Without coercion,
type: integerstill rejects1.0.I will report this in a separate issue.
coerce_valueon,format: binarynow accepts an uploaded file object in a type array.A single
type: stringalready does this.