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.Unscoped

View on GitHub (pinned to 1d6ce99528)

Solutions

  1. Match the preload name exactly to the relation's Go field name (case-sensitive).
  2. Verify nested paths segment by segment (each must be a relation on the respective schema).
  3. Define relation-name constants and reuse them in Preload calls.
  4. 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

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


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