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

  1. Send values matching the map value kind exactly (base-10 ints, true/false, dot decimals, Go duration strings, padded base64)
  2. Validate/coerce map values client-side before encoding them into bracket-syntax params
  3. If you need free-form values, make the value type string and parse downstream yourself
  4. 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

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


AI-assisted analysis of go-kratos/kratos@668db92c2c (2026-08-16). Data as JSON: /api/errors/ce51ca6e2888c90e. Report an issue: GitHub.