go-gorm/gorm · error
%s: unsupported relations for schema %s
Error message
%s: unsupported relations for schema %s
What it means
During Preload execution, each preload name must resolve to a relation on the statement's schema. When the name has no dot (not a nested path) and Relations[name] is nil, GORM returns fmt.Errorf("%s: %w for schema %s", name, gorm.ErrUnsupportedRelation, db.Statement.Schema.Name) - i.e. '<name>: unsupported relations for schema <Schema>'.
Source
Thrown at callbacks/preload.go:163
case reflect.Struct, reflect.Pointer:
reflectValue := rel.Field.ReflectValueOf(db.Statement.Context, rv)
tx := preloadDB(db, reflectValue, reflectValue.Interface())
if err := preloadEntryPoint(tx, nestedJoins, &tx.Statement.Schema.Relationships, preloadMap[name], associationsConds); err != nil {
return err
}
default:
return gorm.ErrInvalidData
}
} else {
tx := db.Table("").Session(&gorm.Session{Context: db.Statement.Context, SkipHooks: db.Statement.SkipHooks})
tx.Statement.ReflectValue = db.Statement.ReflectValue
tx.Statement.Unscoped = db.Statement.Unscoped
if err := preload(tx, rel, append(preloads[name], associationsConds...), preloadMap[name]); err != nil {
return err
}
}
} else {
return fmt.Errorf("%s: %w for schema %s", name, gorm.ErrUnsupportedRelation, db.Statement.Schema.Name)
}
}
return nil
}
func preloadDB(db *gorm.DB, reflectValue reflect.Value, dest interface{}) *gorm.DB {
tx := db.Session(&gorm.Session{Context: db.Statement.Context, NewDB: true, SkipHooks: db.Statement.SkipHooks, Initialized: true})
db.Statement.Settings.Range(func(k, v interface{}) bool {
tx.Statement.Settings.Store(k, v)
return true
})
if err := tx.Statement.Parse(dest); err != nil {
tx.AddError(err)
return tx
}
tx.Statement.ReflectValue = reflectValue
tx.Statement.Unscoped = db.Statement.UnscopedView on GitHub (pinned to 1d6ce99528)
Solutions
- Match the preload name exactly to the relation's Go field name (case-sensitive).
- Verify nested paths segment by segment (each must be a relation on the respective schema).
- Define relation-name constants and reuse them in Preload calls.
- Log db.Statement.Schema Relationships keys in a test that asserts every preload name resolves.
Example fix
// before
db.Preload("Ordrs").Find(&users)
// after
db.Preload("Orders").Find(&users) Defensive patterns
Strategy: validation
Validate before calling
func preloadNamesResolve(db *gorm.DB, model interface{}, names ...string) error {
stmt := &gorm.Statement{DB: db}
if err := stmt.Parse(model); err != nil { return err }
for _, n := range names {
cur := stmt.Schema
for _, seg := range strings.Split(n, ".") {
r := cur.Relationships.Relations[seg]
if r == nil { return fmt.Errorf("preload %q: no relation %s on %s", n, seg, cur.Name) }
cur = r.FieldSchema
}
}
return nil
} Try / catch
if err := db.Preload("Orders").Find(&users).Error; err != nil {
if errors.Is(err, gorm.ErrUnsupportedRelation) {
return errors.New("preload name does not match a relation field")
}
return err
} Prevention
- Store preload names as constants defined beside the model.
- Unit-test each query builder against schema.Parse to catch renames at CI time.
- Remember names are Go field names, case-sensitive - not column or table names.
When it happens
Trigger: db.Preload("Ordrs").Find(&users) with a typo; Preload("Name") where Name is a plain column, not an association; a relation field tagged `gorm:"-"` or of a non-struct kind so it never enters Relationships.
Common situations: String-based preload names silently breaking after model refactors (compiler cannot catch them); copying preload chains between models where the relation does not exist; nested preload paths ('Company.Employees') where an intermediate segment is wrong.
Related errors
- unsupported relations: %s
- unsupported relationship
- failed to assign association %#v, make sure foreign fields e
- model value required when using preload
- failed to get schema
AI-assisted analysis of go-gorm/gorm@1d6ce99528 (2026-08-15).
Data as JSON: /api/errors/7b581a460ee19706.
Report an issue: GitHub.