{"record":{"id":"8193ff99c347406a","repo":"go-kratos/kratos","slug":"too-many-values-for-field-q-s","errorCode":null,"errorMessage":"too many values for field %q: %s","messagePattern":"too many values for field %q: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"encoding/form/proto_decode.go","lineNumber":79,"sourceCode":"\t\t\t}\n\t\t\treturn fmt.Errorf(\"invalid path: %q is not a message\", fieldName)\n\t\t}\n\n\t\tv = v.Mutable(fd).Message()\n\t}\n\tif of := fd.ContainingOneof(); of != nil {\n\t\tif f := v.WhichOneof(of); f != nil {\n\t\t\treturn fmt.Errorf(\"field already set for oneof %q\", of.FullName().Name())\n\t\t}\n\t}\n\tswitch {\n\tcase fd.IsList():\n\t\treturn populateRepeatedField(fd, v.Mutable(fd).List(), values)\n\tcase fd.IsMap():\n\t\treturn populateMapField(fd, v.Mutable(fd).Map(), fieldPath, values)\n\t}\n\tif len(values) > 1 {\n\t\treturn fmt.Errorf(\"too many values for field %q: %s\", fd.FullName().Name(), strings.Join(values, \", \"))\n\t}\n\treturn populateField(fd, v, values[0])\n}\n\nfunc getFieldDescriptor(v protoreflect.Message, fieldName string) protoreflect.FieldDescriptor {\n\tvar (\n\t\tfields = v.Descriptor().Fields()\n\t\tfd     = getDescriptorByFieldAndName(fields, fieldName)\n\t)\n\tif fd == nil {\n\t\tswitch {\n\t\tcase v.Descriptor().FullName() == structMessageFullname:\n\t\t\tfd = fields.ByNumber(structFieldsFieldNumber)\n\t\tcase len(fieldName) > 2 && strings.HasSuffix(fieldName, \"[]\"):\n\t\t\tfd = getDescriptorByFieldAndName(fields, strings.TrimSuffix(fieldName, \"[]\"))\n\t\tdefault:\n\t\t\t// If the type is map, you get the string \"map[kratos]\", where \"map\" is a field of proto and \"kratos\" is a key of map\n\t\t\t// Use symbol . for separating fields/structs. (eg. structfield.field)","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/go-kratos/kratos/blob/668db92c2c001e9552594ba5a8aede8456af6d7e/encoding/form/proto_decode.go#L61-L97","documentation":"Form-binding decoder error for a singular field: the field resolved by the path is neither a list nor a map (the switch's IsList/IsMap cases do not apply), but more than one form value was supplied for that single key. The message lists the field name and all received values joined by commas.","triggerScenarios":"A query string or form body repeating a key bound to a scalar field: `?page=1&page=2` when `page` is int32; multiple selected checkbox/radio inputs posted under one name for a non-repeated proto field; url.Values from a proxy that concatenates duplicate params.","commonSituations":"HTML forms with duplicated input names; query builders appending a default param plus a user-supplied one; client code doing q.Set vs q.Add confusion; field demoted from repeated to singular in the proto while clients still send arrays.","solutions":["Send exactly one value for singular fields: use Set instead of Add (Go) or ensure the client form emits a single input","If multiple values are legitimate, change the proto field to repeated (list) so the IsList branch handles them","If the duplication comes from merging defaults, deduplicate the key (keep first or last) before encoding the query","On the server, pre-process r.URL.Query() to drop extra values for known singular keys before calling the form codec"],"exampleFix":"// proto: int32 page = 1;\n// before: GET /list?page=1&page=2 -> too many values for field \"page\": 1, 2\n// after:  GET /list?page=2\n\n// Go client: use Set, not Add\nq := url.Values{}\nq.Set(\"page\", \"2\")","handlingStrategy":"validation","validationCode":"// Ensure singular fields receive exactly one value before binding\nfunc singleValuesOnly(v url.Values, msg protoreflect.Message) error {\n\tfor key, vals := range v {\n\t\tfd := lookupField(msg, key)\n\t\tif fd == nil {\n\t\t\tcontinue\n\t\t}\n\t\tif !fd.IsList() && !fd.IsMap() && len(vals) > 1 {\n\t\t\treturn fmt.Errorf(\"field %q accepts one value, got %v\", key, vals)\n\t\t}\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"if err := binding.BindQuery(msg, r.URL.Query()); err != nil {\n\tif strings.Contains(err.Error(), \"too many values for field\") {\n\t\treturn errors.BadRequest(\"DUPLICATE_PARAM\", err.Error())\n\t}\n}","preventionTips":["Use url.Values.Set (Go) for scalar params; reserve Add for repeated proto fields","Audit frontend serializers that emit arrays for what the proto models as singular","When demoting repeated->singular in proto, add a temporary server-side check rejecting duplicates with a clear message","Run contract tests with duplicated keys to confirm the API answers 400, not 500"],"tags":["go","kratos","form-binding","protobuf","http","validation"],"backgroundTag":null,"analyzedSha":"668db92c2c001e9552594ba5a8aede8456af6d7e","analyzedAt":"2026-08-16T02:07:20.704Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}