go-gorm/gorm · error

unsupported data type %v for %v on field %s

Error message

unsupported data type %v for %v on field %s

What it means

While guessing a relation, GORM found the field's underlying kind is neither Struct nor Slice, so it cannot build has/belongs-to/many2many semantics. Struct maps to guessGuess, Slice to guessHas; anything else (map, string, int, chan, func, array-of-non-struct after indirection) reaches the default branch and sets schema.err.

Source

Thrown at schema/relationship.go:96

	if relation.FieldSchema, err = getOrParse(fieldValue, schema.cacheStore, schema.namer); err != nil {
		schema.err = fmt.Errorf("failed to parse field: %s, error: %w", field.Name, err)
		return nil
	}

	if hasPolymorphicRelation(field.TagSettings) {
		schema.buildPolymorphicRelation(relation, field)
	} else if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
		schema.buildMany2ManyRelation(relation, field, many2many)
	} else if belongsTo := field.TagSettings["BELONGSTO"]; belongsTo != "" {
		schema.guessRelation(relation, field, guessBelongs)
	} else {
		switch field.IndirectFieldType.Kind() {
		case reflect.Struct:
			schema.guessRelation(relation, field, guessGuess)
		case reflect.Slice:
			schema.guessRelation(relation, field, guessHas)
		default:
			schema.err = fmt.Errorf("unsupported data type %v for %v on field %s", relation.FieldSchema, schema,
				field.Name)
		}
	}

	if relation.Type == has {
		if relation.FieldSchema != relation.Schema && relation.Polymorphic == nil && field.OwnerSchema == nil {
			relation.FieldSchema.Relationships.Mux.Lock()
			relation.FieldSchema.Relationships.Relations["_"+relation.Schema.Name+"_"+relation.Name] = relation
			relation.FieldSchema.Relationships.Mux.Unlock()
		}

		switch field.IndirectFieldType.Kind() {
		case reflect.Struct:
			relation.Type = HasOne
		case reflect.Slice:
			relation.Type = HasMany
		}
	}

View on GitHub (pinned to 1d6ce99528)

Solutions

  1. Implement driver.Valuer and sql.Scanner on the field's type so GORM treats it as a scalar column.
  2. Or add a serializer: `gorm:"serializer:json"`.
  3. Or exclude the field with `gorm:"-"` if it should not be persisted.
  4. If the field should be a relation, change its type to the related struct or a slice of it.

Example fix

// before
type User struct {
    ID    uint
    Roles map[string]bool // unsupported kind: map
}

// after
type User struct {
    ID    uint
    Roles map[string]bool `gorm:"serializer:json"`
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject non-struct, non-slice relation fields before migrate
func validRelationKind(t reflect.Type) bool {
    for t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice || t.Kind() == reflect.Array {
        t = t.Elem()
    }
    return t.Kind() == reflect.Struct
}

Try / catch

if err := db.AutoMigrate(&User{}); err != nil && strings.Contains(err.Error(), "unsupported data type") {
    return fmt.Errorf("check model fields for maps/scalars needing serializer or gorm:\": %w", err)
}

Prevention

When it happens

Trigger: A model field whose indirect type kind is not struct or slice and that reaches the relation builder — typically a custom named type based on a map or string that does not implement Valuer/Scanner, or an array like `[4]byte` used without a serializer tag.

Common situations: Custom type aliases (e.g. `type JSONB map[string]interface{}`) used on models without serializer or Valuer/Scanner; fields typed as channels or funcs; migrating a field from a struct to a scalar type without updating tags.

Related errors


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