{"id":"eb29ca6c7f1c4c0d","repo":"labstack/echo","slug":"binding-element-must-be-a-struct","errorCode":null,"errorMessage":"binding element must be a struct","messagePattern":"binding element must be a struct","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"bind.go","lineNumber":253,"sourceCode":"\t\t\t\tval.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))\n\t\t\t} else if isElemInterface {\n\t\t\t\t// To maintain backward compatibility, we always bind to the first string value\n\t\t\t\t// and not the slice of strings when dealing with map[string]any{}\n\t\t\t\tval.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v[0]))\n\t\t\t} else {\n\t\t\t\tval.SetMapIndex(reflect.ValueOf(k), reflect.ValueOf(v))\n\t\t\t}\n\t\t}\n\t\treturn nil\n\t}\n\n\t// !struct\n\tif typ.Kind() != reflect.Struct {\n\t\tif tag == \"param\" || tag == \"query\" || tag == \"header\" {\n\t\t\t// incompatible type, data is probably to be found in the body\n\t\t\treturn nil\n\t\t}\n\t\treturn errors.New(\"binding element must be a struct\")\n\t}\n\n\tmeta := bindMetaFor(typ)\n\tfor fi := range meta.fields { // iterate over all destination fields\n\t\tfm := &meta.fields[fi]\n\t\tstructField := val.Field(fm.index)\n\t\tif fm.anonymous {\n\t\t\tif structField.Kind() == reflect.Pointer {\n\t\t\t\tstructField = structField.Elem()\n\t\t\t}\n\t\t}\n\t\tif !structField.CanSet() {\n\t\t\tcontinue\n\t\t}\n\t\tstructFieldKind := structField.Kind()\n\t\tinputFieldName := fm.tagName(tag)\n\t\tif fm.anonymous && structFieldKind == reflect.Struct && inputFieldName != \"\" {\n\t\t\t// if anonymous struct with query/param/form tags, report an error","sourceCodeStart":235,"sourceCodeEnd":271,"githubUrl":"https://github.com/labstack/echo/blob/05489dc1730161df26b72d1ae2a3ba6fb8178fc7/bind.go#L235-L271","documentation":"Returned by bindData when the destination passed to form binding is not a struct and not one of the supported map types. Echo's form/path/query/header binder uses reflection to iterate struct fields with binding tags; a non-struct destination (e.g. a bare *string, *int, or *[]string) has no fields to bind into, so the binder refuses it. This only fires for the 'form' source; param/query/header sources silently return nil for incompatible types assuming the data lives in the body.","triggerScenarios":"Calling c.Bind(&someString) or BindBody where the target is *string/*int/*[]string and the Content-Type is application/x-www-form-urlencoded or multipart/form-data, so bindData is invoked with tag \"form\" and a non-struct destination.","commonSituations":"Developer tries to bind a single form field value directly to a primitive instead of wrapping it in a struct. Migrating a JSON handler (which uses the JSON serializer) to form handling and forgetting to change the destination type.","solutions":["Wrap the primitive in a struct with a form tag, e.g. type Req struct{ Name string `form:\"name\"` }, and bind to &Req{}","If you only need a single value use c.FormValue(\"name\") or c.QueryParam(\"name\") instead of Bind","JSON/XML bodies do not go through bindData, so c.Bind with application/json supports any JSON-decodable type"],"exampleFix":"// before\nvar name string\nc.Bind(&name)\n\n// after\nvar req struct {\n    Name string `form:\"name\"`\n}\nc.Bind(&req)","handlingStrategy":"validation","validationCode":"// Before calling c.Bind, verify the destination is a struct pointer\nfunc isStructPtr(v any) bool {\n    t := reflect.TypeOf(v)\n    return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct\n}\nif !isStructPtr(target) {\n    return errors.New(\"bind target must be a pointer to struct\")\n}","typeGuard":"func isStructPtr(v any) bool {\n    t := reflect.TypeOf(v)\n    return t != nil && t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct\n}","tryCatchPattern":"if err := c.Bind(&req); err != nil {\n    if strings.Contains(err.Error(), \"binding element must be a struct\") {\n        return echo.NewHTTPError(http.StatusBadRequest, \"invalid request structure\")\n    }\n    return err\n}","preventionTips":["Always define a request struct type with form/json tags for bindable data","For single values use c.FormValue/c.QueryParam instead of c.Bind","Add unit tests that call c.Bind with your struct to catch type issues at test time"],"tags":["binding","form","reflection","struct"],"analyzedSha":"05489dc1730161df26b72d1ae2a3ba6fb8178fc7","analyzedAt":"2026-08-04T21:32:47.783Z","schemaVersion":2}