go-gorm/gorm · error

unsupported data type: %v for relation %s

Error message

unsupported data type: %v for relation %s

What it means

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).

Source

Thrown at association.go:430

			}
		case schema.HasMany, schema.Many2Many:
			elemType := association.Relationship.Field.IndirectFieldType.Elem()
			oldFieldValue := reflect.Indirect(association.Relationship.Field.ReflectValueOf(association.DB.Statement.Context, source))
			var fieldValue reflect.Value
			if clear {
				fieldValue = reflect.MakeSlice(oldFieldValue.Type(), 0, oldFieldValue.Cap())
			} else {
				fieldValue = reflect.MakeSlice(oldFieldValue.Type(), oldFieldValue.Len(), oldFieldValue.Cap())
				reflect.Copy(fieldValue, oldFieldValue)
			}

			appendToFieldValues := func(ev reflect.Value) {
				if ev.Type().AssignableTo(elemType) {
					fieldValue = reflect.Append(fieldValue, ev)
				} else if ev.Type().Elem().AssignableTo(elemType) {
					fieldValue = reflect.Append(fieldValue, ev.Elem())
				} else {
					association.Error = fmt.Errorf("unsupported data type: %v for relation %s", ev.Type(), association.Relationship.Name)
				}

				if elemType.Kind() == reflect.Struct {
					assignBacks = append(assignBacks, assignBack{Source: source, Dest: ev, Index: fieldValue.Len()})
				}
			}

			processMap := func(mapv reflect.Value) {
				child := reflect.New(association.Relationship.FieldSchema.ModelType)

				switch association.Relationship.Type {
				case schema.HasMany:
					for _, ref := range association.Relationship.References {
						key := reflect.ValueOf(ref.ForeignKey.DBName)
						if ref.OwnPrimaryKey {
							v := ref.PrimaryKey.ReflectValueOf(association.DB.Statement.Context, source)
							mapv.SetMapIndex(key, v)
						} else if ref.PrimaryValue != "" {

View on GitHub (pinned to 1d6ce99528)

Solutions

  1. Append values of exactly the relation's element type (or pointer to it) - check your struct tag's foreignKey model.
  2. Convert loosely-typed data into the concrete slice type before Append.
  3. Inspect association.Error after Append and log ev.Type() vs the relation name to find the mismatch.
  4. After changing a relation's model type, grep for all Append/Replace call sites on that relation.

Example fix

// before
assoc.Append([]interface{}{&Category{Name: "x"}}) // Category is not the relation model

// after
assoc.Append([]*Dog{{Name: "Rex"}})
Defensive patterns

Strategy: type-guard

Validate before calling

func matchRelationType(db *gorm.DB, model interface{}, rel string, vals []interface{}) error {
    stmt := &gorm.Statement{DB: db}
    if err := stmt.Parse(model); err != nil { return err }
    r := stmt.Schema.Relationships.Relations[rel]
    if r == nil { return gorm.ErrUnsupportedRelation }
    for _, v := range vals {
        if !reflect.TypeOf(v).AssignableTo(r.FieldSchema.ModelType) &&
           !(reflect.TypeOf(v).Kind() == reflect.Ptr && reflect.TypeOf(v).Elem().AssignableTo(r.FieldSchema.ModelType)) {
            return fmt.Errorf("value %T not assignable to %s", v, r.FieldSchema.ModelType)
        }
    }
    return nil
}

Type guard

func isRelationValue[T any](v interface{}) bool {
    _, ok := v.(T)
    if !ok {
        p, isPtr := v.(*T)
        return isPtr && p != nil
    }
    return ok
}
// usage: isRelationValue[Dog](item)

Try / catch

if err := assoc.Append(values...); err != nil {
    if strings.Contains(err.Error(), "unsupported data type") {
        // re-typed values; build []*Dog and retry
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of go-gorm/gorm@1d6ce99528 (2026-08-15). Data as JSON: /api/errors/88e21efc06e991ea. Report an issue: GitHub.