go-gorm/gorm · error
failed to get schema
Error message
failed to get schema
What it means
During AutoMigrate, GORM runs RunWithValue to parse the model into a *schema.Statement. If stmt.Schema is nil after parsing, it returns errors.New("failed to get schema"). A nil schema means the value you passed could not be interpreted as a model struct at all, so migration cannot proceed for it.
Source
Thrown at migrator/migrator.go:133
queryTx.DryRun = false
execTx = m.DB.Session(&gorm.Session{Logger: &printSQLLogger{Interface: m.DB.Logger}})
}
return queryTx, execTx
}
// AutoMigrate auto migrate values
func (m Migrator) AutoMigrate(values ...interface{}) error {
for _, value := range m.ReorderModels(values, true) {
queryTx, execTx := m.GetQueryAndExecTx()
if !queryTx.Migrator().HasTable(value) {
if err := execTx.Migrator().CreateTable(value); err != nil {
return err
}
} else {
if err := m.RunWithValue(value, func(stmt *gorm.Statement) error {
if stmt.Schema == nil {
return errors.New("failed to get schema")
}
columnTypes, err := queryTx.Migrator().ColumnTypes(value)
if err != nil {
return err
}
var (
parseIndexes = stmt.Schema.ParseIndexes()
parseCheckConstraints = stmt.Schema.ParseCheckConstraints()
)
for _, dbName := range stmt.Schema.DBNames {
var foundColumn gorm.ColumnType
for _, columnType := range columnTypes {
if columnType.Name() == dbName {
foundColumn = columnType
break
}View on GitHub (pinned to 1d6ce99528)
Solutions
- Pass a pointer to a plain struct: db.AutoMigrate(&User{}, &Order{}).
- Remove nil values from the slice of models before calling AutoMigrate.
- If migrating by table name was intended, use the Migrator SQL APIs (HasTable/CreateTable with a model) instead - AutoMigrate needs a model type.
- Log reflect.TypeOf(value) for each value to find the offending entry.
Example fix
// before
db.AutoMigrate("users", &User{})
// after
db.AutoMigrate(&User{}) Defensive patterns
Strategy: validation
Validate before calling
func validateModels(values ...interface{}) error {
for _, v := range values {
rv := reflect.Indirect(reflect.ValueOf(v))
if !rv.IsValid() || rv.Kind() != reflect.Struct {
return fmt.Errorf("automigrate: %T is not a struct pointer", v)
}
}
return nil
}
// call before db.AutoMigrate(...) Type guard
func isStructPointer(v interface{}) bool {
rv := reflect.ValueOf(v)
return rv.Kind() == reflect.Ptr && rv.Elem().Kind() == reflect.Struct
} Try / catch
if err := db.AutoMigrate(models...); err != nil {
if strings.Contains(err.Error(), "failed to get schema") {
log.Printf("automigrate got a non-struct model; got %v", models)
}
return err
} Prevention
- Always pass &Struct{} literals to AutoMigrate; never table names or nil.
- Lint migration call sites in code review - the argument list is the contract.
- In dynamic registration code, assert types before collecting the model list.
When it happens
Trigger: Calling db.AutoMigrate with a value that schema.Parse cannot handle: a non-struct (string table name, map, int), a nil pointer, a pointer-to-pointer, or a struct whose fields all fail to parse. ReorderModels only reorders; it does not validate.
Common situations: Passing &[]User{} or User{} where a *User was expected; passing a table name string ('users') instead of a model; passing an interface{} holding nil from dynamic registration code; refactoring models so an embedded type became invalid.
Related errors
- unsupported relationship
- unsupported data type: Table not set, please set it like: db
- not support
- unsupported data type
- unsupported relations: %s
AI-assisted analysis of go-gorm/gorm@1d6ce99528 (2026-08-15).
Data as JSON: /api/errors/e9f5db0da372293a.
Report an issue: GitHub.