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

  1. Match bracket keys to the map key type: integer keys for integer-keyed maps, true/false for bool keys, plain strings for string keys
  2. Regenerate client param builders from the current proto so key types follow the schema
  3. If arbitrary keys are required, redefine the map in proto as map<string, T>
  4. 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

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


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