go-kratos/kratos · warning
parsing map key %q: %w
Error message
parsing map key %q: %w
What it means
Form-binding decoder error raised in populateMapField: the key extracted from the map field's bracket syntax (field[key]) could not be parsed into the map's key type via parseField on fd.MapKey(). The %q is the map field's name and the %w wraps the strconv failure for the key string itself.
Source
Thrown at encoding/form/proto_decode.go:147
func populateRepeatedField(fd protoreflect.FieldDescriptor, list protoreflect.List, values []string) error {
for _, value := range values {
v, err := parseField(fd, value)
if err != nil {
return fmt.Errorf("parsing list %q: %w", fd.FullName().Name(), err)
}
list.Append(v)
}
return nil
}
func populateMapField(fd protoreflect.FieldDescriptor, mp protoreflect.Map, fieldPath []string, values []string) error {
_, keyName, err := parseURLQueryMapKey(strings.Join(fieldPath, fieldSeparator))
if err != nil {
return err
}
key, err := parseField(fd.MapKey(), keyName)
if err != nil {
return fmt.Errorf("parsing map key %q: %w", fd.FullName().Name(), err)
}
value, err := parseField(fd.MapValue(), values[len(values)-1])
if err != nil {
return fmt.Errorf("parsing map value %q: %w", fd.FullName().Name(), err)
}
mp.Set(key.MapKey(), value)
return nil
}
func parseField(fd protoreflect.FieldDescriptor, value string) (protoreflect.Value, error) {
switch fd.Kind() {
case protoreflect.BoolKind:
v, err := strconv.ParseBool(value)
if err != nil {
return protoreflect.Value{}, err
}
return protoreflect.ValueOfBool(v), nil
case protoreflect.EnumKind:View on GitHub (pinned to 668db92c2c)
Solutions
- Match bracket keys to the map key type: integer keys for integer-keyed maps, true/false for bool keys, plain strings for string keys
- Regenerate client param builders from the current proto so key types follow the schema
- If arbitrary keys are required, redefine the map in proto as map<string, T>
- URL-encode keys properly so brackets/content survive transport into the bracket parser
Example fix
// proto: map<int32, string> labels = 1; // before: GET /x?labels[abc]=v -> parsing map key "labels": strconv.ParseInt: parsing "abc": invalid syntax // after: GET /x?labels[1]=v
Defensive patterns
Strategy: validation
Validate before calling
// Validate bracket map keys against the proto key kind before binding
func validateMapKeys(q url.Values, keyKind map[string]protoreflect.Kind) error {
pattern := map[protoreflect.Kind]*regexp.Regexp{
protoreflect.Int32Kind: regexp.MustCompile(`^-?\d+$`),
protoreflect.Uint32Kind: regexp.MustCompile(`^\d+$`),
protoreflect.BoolKind: regexp.MustCompile(`^(true|false)$`),
}
for key := range q {
i := strings.IndexByte(key, '[')
if i < 0 {
continue
}
field := key[:i]
k := keyKind[field]
if re, ok := pattern[k]; ok && !re.MatchString(strings.TrimSuffix(key[i+1:], "]")) {
return fmt.Errorf("bad map key in %q for kind %v", key, k)
}
}
return nil
} Try / catch
if err := binding.BindQuery(msg, q); err != nil {
if strings.Contains(err.Error(), "parsing map key") {
return errors.BadRequest("BAD_MAP_KEY", err.Error())
}
} Prevention
- Document the map key type next to every bracket-syntax parameter
- Generate map params from typed client objects (map[int32]T -> m[1]=...), not from string maps
- Prefer map<string,T> in protos meant for form binding to sidestep key coercion entirely
- URL-encode bracket keys so special characters survive into the key parser
When it happens
Trigger: Query keys where the bracketed key does not match the proto map key kind: map<int32,string> with `labels[abc]=x`; map<bool,string> with `flags[maybe]=x`; map<string,string> with an unparseable URL-encoded key; map<uint64,...> with a negative key `m[-1]=v`. The key name is first recovered by parseURLQueryMapKey from the joined field path, then type-converted.
Common situations: Using arbitrary string keys against a numeric-keyed map defined for compactness; frontend generating map params from object keys without knowing the proto key type; URL encoding issues splitting the bracket key; proto evolution changing key type from string to int while clients keep old keys.
Related errors
- parsing map value %q: %w
- invalid path: %q is not a message
- field already set for oneof %q
- too many values for field %q: %s
- parsing field %q: %w
AI-assisted analysis of go-kratos/kratos@668db92c2c (2026-08-16).
Data as JSON: /api/errors/5a3ad0ff2655656a.
Report an issue: GitHub.