Summary
internal/apiform preserves float32 precision when encoding a scalar form field, but loses that guarantee when the same values are encoded in a comma-form array.
For FormatComma, both reflect.Float32 and reflect.Float64 currently use:
strconv.FormatFloat(item.Float(), 'f', -1, 64)
Because reflection exposes the numeric value through a float64, a source float32(0.1) can therefore become 0.10000000149011612 in the multipart field.
Reproduction
On current main (d082a010f7c6cacf407d8a1581446a7857f9f1bb), encoding:
map[string]any{
"value": []float32{0.1, 1.5},
}
with FormatComma produces a field body equivalent to:
while a scalar float32(0.1) already follows the dedicated primitive branch and produces:
Root cause
The scalar encoder distinguishes source widths:
case reflect.Float32:
strconv.FormatFloat(val.Float(), 'f', -1, 32)
case reflect.Float64:
strconv.FormatFloat(val.Float(), 'f', -1, 64)
The FormatComma array encoder combines those cases and always passes bitSize=64.
Expected behavior
A float32 should have the same textual representation whether it is encoded as a scalar form field or as an element of a comma-form array. float64 behavior should remain unchanged.
Suggested fix
Split the comma-array floating-point branch into reflect.Float32 and reflect.Float64, using bitSize=32 and bitSize=64 respectively, and add a regression for a comma-form []float32{0.1, 1.5}.
Impact
This is request serialization correctness. APIs receiving comma-delimited numeric form parameters can observe values containing precision artifacts that were not present in the source float32 inputs.
Summary
internal/apiformpreservesfloat32precision when encoding a scalar form field, but loses that guarantee when the same values are encoded in a comma-form array.For
FormatComma, bothreflect.Float32andreflect.Float64currently use:Because reflection exposes the numeric value through a
float64, a sourcefloat32(0.1)can therefore become0.10000000149011612in the multipart field.Reproduction
On current
main(d082a010f7c6cacf407d8a1581446a7857f9f1bb), encoding:with
FormatCommaproduces a field body equivalent to:while a scalar
float32(0.1)already follows the dedicated primitive branch and produces:Root cause
The scalar encoder distinguishes source widths:
The
FormatCommaarray encoder combines those cases and always passesbitSize=64.Expected behavior
A
float32should have the same textual representation whether it is encoded as a scalar form field or as an element of a comma-form array.float64behavior should remain unchanged.Suggested fix
Split the comma-array floating-point branch into
reflect.Float32andreflect.Float64, usingbitSize=32andbitSize=64respectively, and add a regression for a comma-form[]float32{0.1, 1.5}.Impact
This is request serialization correctness. APIs receiving comma-delimited numeric form parameters can observe values containing precision artifacts that were not present in the source
float32inputs.