Skip to content

Query encoder drops int8/uint8 values and widens float32 precision #75

Description

@sylvesterkaczmarek

Summary

internal/apiquery does not preserve the value semantics of several Go primitive numeric types.

  • int8 and uint8 are not handled by encodePrimitive, so those values produce no query pair at all.
  • float32 is handled together with float64 using strconv.FormatFloat(..., 64), so a value such as float32(0.1) is widened before formatting and can be serialized as 0.10000000149011612 instead of 0.1.

This is inconsistent with the sibling multipart/form encoder, whose primitive path supports int8/uint8 and formats float32 with a 32-bit precision argument.

Reproduction

On current main (d082a010f7c6cacf407d8a1581446a7857f9f1bb), these calls exercise the problem directly:

values, _ := Marshal(map[string]any{"value": int8(-8)})
fmt.Println(values.Encode())
// current: ""
// expected: "value=-8"

values, _ = Marshal(map[string]any{"value": uint8(8)})
fmt.Println(values.Encode())
// current: ""
// expected: "value=8"

values, _ = Marshal(map[string]any{"value": float32(0.1)})
fmt.Println(values.Get("value"))
// current: "0.10000000149011612"
// expected: "0.1"

Root cause

internal/apiquery/encoder.go currently handles:

case reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64:
...
case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64:
...
case reflect.Float32, reflect.Float64:
    strconv.FormatFloat(value.Float(), 'f', -1, 64)

The narrow 8-bit integer kinds are missing, and the float branch always asks FormatFloat to preserve 64-bit precision even when the source value is a float32.

Expected behavior

The query encoder should serialize supported Go primitive values without silently dropping them or exposing precision artifacts introduced only by reflection widening:

  • int8 should follow the other signed integer kinds;
  • uint8 should follow the other unsigned integer kinds;
  • float32 should use bitSize=32;
  • float64 should retain bitSize=64.

Suggested fix

Add the missing integer kinds and split the float formatting cases by source width. Add focused table-driven regressions for int8, uint8, and float32(0.1).

Impact

This is query-serialization correctness. Callers using these legitimate Go primitive types can currently send a different numeric value than intended, or omit the parameter entirely, without receiving an error.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions