{"record":{"id":"88e21efc06e991ea","repo":"go-gorm/gorm","slug":"unsupported-data-type-v-for-relation-s","errorCode":null,"errorMessage":"unsupported data type: %v for relation %s","messagePattern":"unsupported data type: (.+?) for relation (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"association.go","lineNumber":430,"sourceCode":"\t\t\t}\n\t\tcase schema.HasMany, schema.Many2Many:\n\t\t\telemType := association.Relationship.Field.IndirectFieldType.Elem()\n\t\t\toldFieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source))\n\t\t\tvar fieldValue reflect.Value\n\t\t\tif clear {\n\t\t\t\tfieldValue = reflect.MakeSlice(oldFieldValue.Type(), 0, oldFieldValue.Cap())\n\t\t\t} else {\n\t\t\t\tfieldValue = reflect.MakeSlice(oldFieldValue.Type(), oldFieldValue.Len(), oldFieldValue.Cap())\n\t\t\t\treflect.Copy(fieldValue, oldFieldValue)\n\t\t\t}\n\n\t\t\tappendToFieldValues := func(ev reflect.Value) {\n\t\t\t\tif ev.Type().AssignableTo(elemType) {\n\t\t\t\t\tfieldValue = reflect.Append(fieldValue, ev)\n\t\t\t\t} else if ev.Type().Elem().AssignableTo(elemType) {\n\t\t\t\t\tfieldValue = reflect.Append(fieldValue, ev.Elem())\n\t\t\t\t} else {\n\t\t\t\t\tassociation.Error = fmt.Errorf(\"unsupported data type: %v for relation %s\", ev.Type(), association.Relationship.Name)\n\t\t\t\t}\n\n\t\t\t\tif elemType.Kind() == reflect.Struct {\n\t\t\t\t\tassignBacks = append(assignBacks, assignBack{Source: source, Dest: ev, Index: fieldValue.Len()})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tprocessMap := func(mapv reflect.Value) {\n\t\t\t\tchild := reflect.New(association.Relationship.FieldSchema.ModelType)\n\n\t\t\t\tswitch association.Relationship.Type {\n\t\t\t\tcase schema.HasMany:\n\t\t\t\t\tfor _, ref := range association.Relationship.References {\n\t\t\t\t\t\tkey := reflect.ValueOf(ref.ForeignKey.DBName)\n\t\t\t\t\t\tif ref.OwnPrimaryKey {\n\t\t\t\t\t\t\tv := ref.PrimaryKey.ReflectValueOf(association.DB.Statement.Context, source)\n\t\t\t\t\t\t\tmapv.SetMapIndex(key, v)\n\t\t\t\t\t\t} else if ref.PrimaryValue != \"\" {","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/go-gorm/gorm/blob/1d6ce99528060be18a42be09aca8d39efcb47f28/association.go#L412-L448","documentation":"While appending association values (Association.Append / Replace internals in association.go), each element ev must be assignable to the relation's element type elemType (directly or via pointer indirection). If neither ev.Type().AssignableTo(elemType) nor ev.Type().Elem().AssignableTo(elemType) holds, association.Error is set to fmt.Errorf(\"unsupported data type: %v for relation %s\", ev.Type(), association.Relationship.Name).","triggerScenarios":"Appending values whose type does not match the relation's declared model: appending *Category to a Pets []*Dog relation, appending a map/string where a struct is expected (the map path handles schema shape separately), or mixing pointer/non-pointer element types that do not line up with elemType.","commonSituations":"Generic code that accumulates interface{} values and appends them to associations; refactoring a relation's model type (Pet -> Dog) while callers still build old-type slices; JSON-decoded []interface{} passed straight into Append.","solutions":["Append values of exactly the relation's element type (or pointer to it) - check your struct tag's foreignKey model.","Convert loosely-typed data into the concrete slice type before Append.","Inspect association.Error after Append and log ev.Type() vs the relation name to find the mismatch.","After changing a relation's model type, grep for all Append/Replace call sites on that relation."],"exampleFix":"// before\nassoc.Append([]interface{}{&Category{Name: \"x\"}}) // Category is not the relation model\n\n// after\nassoc.Append([]*Dog{{Name: \"Rex\"}})","handlingStrategy":"type-guard","validationCode":"func matchRelationType(db *gorm.DB, model interface{}, rel string, vals []interface{}) error {\n    stmt := &gorm.Statement{DB: db}\n    if err := stmt.Parse(model); err != nil { return err }\n    r := stmt.Schema.Relationships.Relations[rel]\n    if r == nil { return gorm.ErrUnsupportedRelation }\n    for _, v := range vals {\n        if !reflect.TypeOf(v).AssignableTo(r.FieldSchema.ModelType) &&\n           !(reflect.TypeOf(v).Kind() == reflect.Ptr && reflect.TypeOf(v).Elem().AssignableTo(r.FieldSchema.ModelType)) {\n            return fmt.Errorf(\"value %T not assignable to %s\", v, r.FieldSchema.ModelType)\n        }\n    }\n    return nil\n}","typeGuard":"func isRelationValue[T any](v interface{}) bool {\n    _, ok := v.(T)\n    if !ok {\n        p, isPtr := v.(*T)\n        return isPtr && p != nil\n    }\n    return ok\n}\n// usage: isRelationValue[Dog](item)","tryCatchPattern":"if err := assoc.Append(values...); err != nil {\n    if strings.Contains(err.Error(), \"unsupported data type\") {\n        // re-typed values; build []*Dog and retry\n    }\n}","preventionTips":["Type association payloads as concrete slices ([]*Dog), never []interface{}.","After changing a relation's model type, fix every Append/Replace call site in the same commit."],"tags":["gorm","associations","type-mismatch","append"],"backgroundTag":null,"analyzedSha":"1d6ce99528060be18a42be09aca8d39efcb47f28","analyzedAt":"2026-08-15T13:01:23.433Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}