go-gorm/gorm · error

slice data #%v is invalid: unsupported data

Error message

slice data #%v is invalid: unsupported data

What it means

In the create callback for slice destinations, each element is retrieved with reflect.Indirect(stmt.ReflectValue.Index(i)); if the resulting value is not valid (rv.IsValid() == false), GORM adds fmt.Errorf("slice data #%v is invalid: %w", i, gorm.ErrInvalidData) and aborts. An invalid reflect value here means the slice slot holds something unrepresentable - classically a nil element in a slice of non-pointer structs, or a nil interface element.

Source

Thrown at callbacks/create.go:291

		}

		switch stmt.ReflectValue.Kind() {
		case reflect.Slice, reflect.Array:
			rValLen := stmt.ReflectValue.Len()
			if rValLen == 0 {
				stmt.AddError(gorm.ErrEmptySlice)
				return
			}

			stmt.SQL.Grow(rValLen * 18)
			stmt.Vars = make([]interface{}, 0, rValLen*len(values.Columns))
			values.Values = make([][]interface{}, rValLen)

			defaultValueFieldsHavingValue := map[*schema.Field][]interface{}{}
			for i := 0; i < rValLen; i++ {
				rv := reflect.Indirect(stmt.ReflectValue.Index(i))
				if !rv.IsValid() {
					stmt.AddError(fmt.Errorf("slice data #%v is invalid: %w", i, gorm.ErrInvalidData))
					return
				}

				values.Values[i] = make([]interface{}, len(values.Columns))
				for idx, column := range values.Columns {
					field := stmt.Schema.FieldsByDBName[column.Name]
					if values.Values[i][idx], isZero = field.ValueOf(stmt.Context, rv); isZero {
						if field.DefaultValueInterface != nil {
							values.Values[i][idx] = field.DefaultValueInterface
							stmt.AddError(field.Set(stmt.Context, rv, field.DefaultValueInterface))
						} else if field.AutoCreateTime > 0 || field.AutoUpdateTime > 0 {
							stmt.AddError(field.Set(stmt.Context, rv, curTime))
							values.Values[i][idx], _ = field.ValueOf(stmt.Context, rv)
						}
					} else if field.AutoUpdateTime > 0 && updateTrackTime {
						stmt.AddError(field.Set(stmt.Context, rv, curTime))
						values.Values[i][idx], _ = field.ValueOf(stmt.Context, rv)
					}

View on GitHub (pinned to 1d6ce99528)

Solutions

  1. Filter nil/invalid elements out of the slice before Create.
  2. Prefer []*User (Create skips nil pointers for typed slices is NOT true - filter anyway) and construct slices with exact length via make([]*User, 0, n) + append.
  3. Validate each element with reflect or a plain nil check in batch-building code.
  4. If holes are expected, use CreateInBatches on cleaned sub-slices.

Example fix

// before
users := []*User{u1, nil, u3}
db.Create(&users) // slice data #1 is invalid

// after
clean := users[:0]
for _, u := range users {
    if u != nil { clean = append(clean, u) }
}
db.Create(&clean)
Defensive patterns

Strategy: validation

Validate before calling

func dropInvalid[T any](in []*T) []*T {
    out := make([]*T, 0, len(in))
    for _, v := range in {
        if v != nil { out = append(out, v) }
    }
    return out
}
// before create:
db.Create(&dropInvalid(users))

Type guard

func allValid[T any](in []*T) bool {
    for _, v := range in { if v == nil { return false } }
    return true
}

Try / catch

if err := db.Create(&users).Error; err != nil {
    if errors.Is(err, gorm.ErrInvalidData) {
        // clean the slice (remove nils) and retry once
    }
    return err
}

Prevention

When it happens

Trigger: db.Create(&users) where users is []User and one element is the zero struct is fine - the real trigger is []interface{} or []*User containing nil, or a slice of a type whose element cannot be indirected to a valid value (e.g. nil map/chan-typed elements).

Common situations: Building []interface{} from mixed sources (JSON decode, goroutine fan-in) and inserting without filtering nils; []*User with a nil appended as a placeholder; partial batch construction where an index was allocated but never filled.

Related errors


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