{"record":{"id":"5a3ad0ff2655656a","repo":"go-kratos/kratos","slug":"parsing-map-key-q-w","errorCode":null,"errorMessage":"parsing map key %q: %w","messagePattern":"parsing map key %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"encoding/form/proto_decode.go","lineNumber":147,"sourceCode":"func populateRepeatedField(fd protoreflect.FieldDescriptor, list protoreflect.List, values []string) error {\n\tfor _, value := range values {\n\t\tv, err := parseField(fd, value)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"parsing list %q: %w\", fd.FullName().Name(), err)\n\t\t}\n\t\tlist.Append(v)\n\t}\n\treturn nil\n}\n\nfunc populateMapField(fd protoreflect.FieldDescriptor, mp protoreflect.Map, fieldPath []string, values []string) error {\n\t_, keyName, err := parseURLQueryMapKey(strings.Join(fieldPath, fieldSeparator))\n\tif err != nil {\n\t\treturn err\n\t}\n\tkey, err := parseField(fd.MapKey(), keyName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing map key %q: %w\", fd.FullName().Name(), err)\n\t}\n\tvalue, err := parseField(fd.MapValue(), values[len(values)-1])\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing map value %q: %w\", fd.FullName().Name(), err)\n\t}\n\tmp.Set(key.MapKey(), value)\n\treturn nil\n}\n\nfunc parseField(fd protoreflect.FieldDescriptor, value string) (protoreflect.Value, error) {\n\tswitch fd.Kind() {\n\tcase protoreflect.BoolKind:\n\t\tv, err := strconv.ParseBool(value)\n\t\tif err != nil {\n\t\t\treturn protoreflect.Value{}, err\n\t\t}\n\t\treturn protoreflect.ValueOfBool(v), nil\n\tcase protoreflect.EnumKind:","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/go-kratos/kratos/blob/668db92c2c001e9552594ba5a8aede8456af6d7e/encoding/form/proto_decode.go#L129-L165","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// proto: map<int32, string> labels = 1;\n// before: GET /x?labels[abc]=v -> parsing map key \"labels\": strconv.ParseInt: parsing \"abc\": invalid syntax\n// after:  GET /x?labels[1]=v","handlingStrategy":"validation","validationCode":"// Validate bracket map keys against the proto key kind before binding\nfunc validateMapKeys(q url.Values, keyKind map[string]protoreflect.Kind) error {\n\tpattern := map[protoreflect.Kind]*regexp.Regexp{\n\t\tprotoreflect.Int32Kind:  regexp.MustCompile(`^-?\\d+$`),\n\t\tprotoreflect.Uint32Kind: regexp.MustCompile(`^\\d+$`),\n\t\tprotoreflect.BoolKind:   regexp.MustCompile(`^(true|false)$`),\n\t}\n\tfor key := range q {\n\t\ti := strings.IndexByte(key, '[')\n\t\tif i < 0 {\n\t\t\tcontinue\n\t\t}\n\t\tfield := key[:i]\n\t\tk := keyKind[field]\n\t\tif re, ok := pattern[k]; ok && !re.MatchString(strings.TrimSuffix(key[i+1:], \"]\")) {\n\t\t\treturn fmt.Errorf(\"bad map key in %q for kind %v\", key, k)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := binding.BindQuery(msg, q); err != nil {\n\tif strings.Contains(err.Error(), \"parsing map key\") {\n\t\treturn errors.BadRequest(\"BAD_MAP_KEY\", err.Error())\n\t}\n}","preventionTips":["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"],"tags":["go","kratos","form-binding","protobuf","map","validation"],"backgroundTag":null,"analyzedSha":"668db92c2c001e9552594ba5a8aede8456af6d7e","analyzedAt":"2026-08-16T02:07:20.704Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}