{"record":{"id":"ce51ca6e2888c90e","repo":"go-kratos/kratos","slug":"parsing-map-value-q-w","errorCode":null,"errorMessage":"parsing map value %q: %w","messagePattern":"parsing map value %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"encoding/form/proto_decode.go","lineNumber":151,"sourceCode":"\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:\n\t\tenum, err := protoregistry.GlobalTypes.FindEnumByName(fd.Enum().FullName())\n\t\tswitch {\n\t\tcase errors.Is(err, protoregistry.NotFound):\n\t\t\treturn protoreflect.Value{}, fmt.Errorf(\"enum %q is not registered\", fd.Enum().FullName())","sourceCodeStart":133,"sourceCodeEnd":169,"githubUrl":"https://github.com/go-kratos/kratos/blob/668db92c2c001e9552594ba5a8aede8456af6d7e/encoding/form/proto_decode.go#L133-L169","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// proto: map<string, int32> counts = 1;\n// before: GET /x?counts[a]=many -> parsing map value \"counts\": strconv.ParseInt: parsing \"many\": invalid syntax\n// after:  GET /x?counts[a]=42","handlingStrategy":"validation","validationCode":"// Validate map values against the proto value kind before binding\nfunc validateMapValues(q url.Values, valKind map[string]func(string) error) error {\n\tfor key, vals := range q {\n\t\tfield := strings.SplitN(key, \"[\", 2)[0]\n\t\tcheck, ok := valKind[field]\n\t\tif !ok {\n\t\t\tcontinue\n\t\t}\n\t\tif err := check(vals[len(vals)-1]); err != nil { // codec uses the LAST value\n\t\t\treturn fmt.Errorf(\"%s value: %w\", key, err)\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 value\") {\n\t\treturn errors.BadRequest(\"BAD_MAP_VALUE\", err.Error())\n\t}\n}","preventionTips":["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"],"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"}