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
- Filter nil/invalid elements out of the slice before Create.
- 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.
- Validate each element with reflect or a plain nil check in batch-building code.
- 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
- Build batches with append, never by index assignment into a pre-sized slice.
- Filter nils at the boundary where external data becomes models.
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
- unsupported data type: %+v
- violates check constraint
- unsupported relationship
- record not found
- failed to get schema
AI-assisted analysis of go-gorm/gorm@1d6ce99528 (2026-08-15).
Data as JSON: /api/errors/7dacdc5e20330086.
Report an issue: GitHub.