-
Notifications
You must be signed in to change notification settings - Fork 31
Description
Describe the bug
When using a struct containing a slice as a key in the TypeSchemas map in jsonschema.ForOptions, the program panics with runtime error: hash of unhashable type. This occurs because slices are not hashable in Go and cannot be used as map keys.
To Reproduce
Steps to reproduce the behavior:
- Define a struct that contains a slice field.
- Create an instance of this struct and use it as a key in a
map[any]*jsonschema.Schema. - Assign this map to the
TypeSchemasfield ofjsonschema.ForOptions. - Attempt to print or otherwise inspect the
jsonschema.ForOptionsstruct, which will trigger the panic.
Here is a minimal code example that reproduces the bug:
Go playground link: https://go.dev/play/p/N69KcaSAjzZ
package main
import (
"bytes"
"fmt"
"github.com/google/jsonschema-go/jsonschema"
)
type ID struct {
seg []int
}
func (t ID) String() string {
buf := bytes.Buffer{}
for i, s := range t.seg {
if i > 0 {
buf.WriteString(".")
}
buf.WriteString(fmt.Sprintf("%02d", s))
}
return buf.String()
}
func main() {
m := map[any]*jsonschema.Schema{
ID{}: {Type: "string"},
}
forOpts := jsonschema.ForOptions{TypeSchemas: m}
fmt.Printf("%+v\n", forOpts)
}Expected behavior
The program should not panic. There are a few possible expected behaviors:
- The library could detect the unhashable key and provide a clear error message, rather than panicking. (example: switching from
anytocomparable) - The library could internally handle such cases, perhaps by converting the key to a string representation if it implements
fmt.Stringer, before using it in a map. I don't like this as it feels brittle. - Create an interface with a method
Hash() int64but there are a few proposals about hashing:
Logs
panic: runtime error: hash of unhashable type main.ID
goroutine 1 [running]:
main.main()
/Users/julien/perso/bug01/main.go:26 +0x6c
exit status 2
Additional context
I wanted to provide a custom schema for a type that has a custom string representation (i.e., it implements fmt.Stringer). The library should ideally support this use case without causing a panic at runtime. The fact that the panic occurs not on map creation but on inspection of the ForOptions struct makes the bug particularly difficult to debug.
I discovered this when working on an MCP server: https://github.com/veggiemonk/backlog/pull/4/files#diff-10ba8694f076394780ca09af7b0f491fe66afb89144fe6f7821623b957a6c5e5R276
The ID complies with interfaces fmt.Stringer, json.Marshaler, etc...
https://github.com/veggiemonk/backlog/pull/4/files#diff-a702fe5fe5e8d999bb59813855e3e2041a66a029f4d019e3daba30d993773ed4R20-R25
I tried Initializing the slices in the struct:
https://github.com/veggiemonk/backlog/pull/4/files#diff-a702fe5fe5e8d999bb59813855e3e2041a66a029f4d019e3daba30d993773ed4R27
But it always crash.