Go version
go version go1.27.0 darwin/arm64 (also reproduces with gotip at 714d9af)
Output of go env in your module/workspace:
AR='ar'
CC='clang'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='clang++'
GO111MODULE=''
GOARCH='arm64'
GOARM64='v8.0'
GOAUTH='netrc'
GOBIN='/Users/redacted/go/bin'
GOCACHE='/Users/redacted/Library/Caches/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/Users/redacted/Library/Application Support/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOHOSTARCH='arm64'
GOHOSTOS='darwin'
GOINSECURE=''
GOMOD='/Users/redacted/src/example/go.mod'
GOMODCACHE='/Users/redacted/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='darwin'
GOPACKAGESDRIVER=''
GOPATH='/Users/redacted/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/Users/redacted/sdk/go1.27.0'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/Users/redacted/Library/Application Support/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOVCS=''
GOWORK=''
What did you do?
package main
import (
"encoding/json"
"fmt"
)
func main() {
b, err := json.Marshal(map[float64]int{1.5: 1})
fmt.Printf("Marshal: out=%q err=%v\n", b, err)
var m map[float64]int
err = json.Unmarshal([]byte(`{"1.5":1}`), &m)
fmt.Printf("Unmarshal: got=%v err=%v\n", m, err)
}
What did you see happen?
With go1.27.0 and gotip (jsonv2 is the default):
Marshal: out="{\"1.5\":1}" err=<nil>
Unmarshal: got=map[1.5:1] err=<nil>
With go1.24.0, go1.25.5, and go1.27.0 GOEXPERIMENT=nojsonv2:
Marshal: out="" err=json: unsupported type: map[float64]int
Unmarshal: got=map[] err=json: cannot unmarshal object into Go value of type map[float64]int
Same for map[float32]V and named floating-point key types. NaN and infinite keys still error, though with *json.UnsupportedValueError rather than *json.UnsupportedTypeError.
Floating-point kinds seem to be the only key kinds that succeed silently on a non-empty map. Other unsupported key kinds still error:
map[struct{}]int non-empty out="" err=json: unsupported value: jsontext: object member name must be a string after offset 2
map[[2]int]int non-empty out="" err=json: unsupported value: jsontext: object member name must be a string after offset 2
map[complex128]int non-empty out="" err=json: unsupported type: complex128
map[bool]int non-empty out="" err=json: unsupported value: jsontext: object member name must be a string after offset 2
map[float64]int non-empty out="{\"1.5\":1}" err=<nil>
map[float32]int non-empty out="{\"1.5\":1}" err=<nil>
What did you expect to see?
The same behavior as Go 1.26. The doc comment still says:
Map values encode as JSON objects. The map's key type must either be a string, an integer type, or implement [encoding.TextMarshaler].
and the Go 1.27 release notes say "Marshaling and unmarshaling behavior is preserved, but the exact text of error messages may differ." This is a behavior change, not an error-text change: output produced by 1.27 here can't be read back by Go ≤ 1.26.
#79938 is related, but it was closed on the reasoning that the check is merely deferred and the error is eventually surfaced once a map entry is inserted. That holds for struct/array/bool keys, but not for float keys: the map above is non-empty and never errors, in either direction. Looks like the same class of regression as #81061 and #81355. The cause seems to be that nothing in the v1 compatibility layer restricts map key kinds, and the float arshaler quotes itself in object-name position.
Go version
go version go1.27.0 darwin/arm64 (also reproduces with gotip at 714d9af)
Output of
go envin your module/workspace:What did you do?
What did you see happen?
With go1.27.0 and gotip (jsonv2 is the default):
With go1.24.0, go1.25.5, and go1.27.0
GOEXPERIMENT=nojsonv2:Same for
map[float32]Vand named floating-point key types. NaN and infinite keys still error, though with*json.UnsupportedValueErrorrather than*json.UnsupportedTypeError.Floating-point kinds seem to be the only key kinds that succeed silently on a non-empty map. Other unsupported key kinds still error:
What did you expect to see?
The same behavior as Go 1.26. The doc comment still says:
and the Go 1.27 release notes say "Marshaling and unmarshaling behavior is preserved, but the exact text of error messages may differ." This is a behavior change, not an error-text change: output produced by 1.27 here can't be read back by Go ≤ 1.26.
#79938 is related, but it was closed on the reasoning that the check is merely deferred and the error is eventually surfaced once a map entry is inserted. That holds for struct/array/bool keys, but not for float keys: the map above is non-empty and never errors, in either direction. Looks like the same class of regression as #81061 and #81355. The cause seems to be that nothing in the v1 compatibility layer restricts map key kinds, and the float arshaler quotes itself in object-name position.