go-kratos/kratos · warning
parsing map value %q: %w
Error message
parsing map value %q: %w
What it means
Form-binding decoder error raised in populateMapField when the map's VALUE string cannot be parsed into the map value kind: parseField on fd.MapValue() failed on the last submitted value for the key (values[len(values)-1]). %q is the map field name; %w wraps the underlying strconv/parse error for the value.
Source
Thrown at encoding/form/proto_decode.go:151
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:
enum, err := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName())
switch {
case errors.Is(err, protoregistry.NotFound):
return protoreflect.Value{}, fmt.Errorf("enum %q is not registered", fd.Enum().FullName())View on GitHub (pinned to 668db92c2c)
Solutions
- Send values matching the map value kind exactly (base-10 ints, true/false, dot decimals, Go duration strings, padded base64)
- Validate/coerce map values client-side before encoding them into bracket-syntax params
- If you need free-form values, make the value type string and parse downstream yourself
- For multiple values under one map key, note only the last counts - fix the client to emit one entry per key
Example fix
// proto: map<string, int32> counts = 1; // before: GET /x?counts[a]=many -> parsing map value "counts": strconv.ParseInt: parsing "many": invalid syntax // after: GET /x?counts[a]=42
Defensive patterns
Strategy: validation
Validate before calling
// Validate map values against the proto value kind before binding
func validateMapValues(q url.Values, valKind map[string]func(string) error) error {
for key, vals := range q {
field := strings.SplitN(key, "[", 2)[0]
check, ok := valKind[field]
if !ok {
continue
}
if err := check(vals[len(vals)-1]); err != nil { // codec uses the LAST value
return fmt.Errorf("%s value: %w", key, err)
}
}
return nil
} Try / catch
if err := binding.BindQuery(msg, q); err != nil {
if strings.Contains(err.Error(), "parsing map value") {
return errors.BadRequest("BAD_MAP_VALUE", err.Error())
}
} Prevention
- Send one value per map key; the codec ignores all but the last
- Use exact literals: integers base-10, booleans true/false, durations in Go syntax
- If values are free-form, make the map value type string and validate in the handler
- Contract-test map params with the same builder the frontend ships
When it happens
Trigger: Map entries whose value does not match the value type: map<string,int32> with `counts[a]=many`; map<string,bool> with `flags[x]=1` (strconv.ParseBool actually accepts 1, but 'yes' fails); map<string,Duration> with `d[k]=3x`; map<string,bytes> with invalid base64 values. Only the last value for the key is attempted, so earlier duplicates are silently ignored.
Common situations: Metadata maps (map<string,string>) repurposed to carry numbers with units; clients writing human booleans ('yes'/'no'); localized numbers in map values; base64 values mangled by URL length limits or encoding.
Related errors
- parsing map key %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/ce51ca6e2888c90e.
Report an issue: GitHub.