{"record":{"id":"40dd71d0586d32fd","repo":"go-gorm/gorm","slug":"model-value-required-when-using-preload","errorCode":null,"errorMessage":"model value required when using preload","messagePattern":"model value required when using preload","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"callbacks/query.go","lineNumber":280,"sourceCode":"\t\t\t\t\t})\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tdb.Statement.AddClause(fromClause)\n\t\t} else {\n\t\t\tdb.Statement.AddClauseIfNotExists(clause.From{})\n\t\t}\n\n\t\tdb.Statement.AddClauseIfNotExists(clauseSelect)\n\n\t\tdb.Statement.Build(db.Statement.BuildClauses...)\n\t}\n}\n\nfunc Preload(db *gorm.DB) {\n\tif db.Error == nil && len(db.Statement.Preloads) > 0 {\n\t\tif db.Statement.Schema == nil {\n\t\t\tdb.AddError(fmt.Errorf(\"%w when using preload\", gorm.ErrModelValueRequired))\n\t\t\treturn\n\t\t}\n\n\t\tjoins := make([]string, 0, len(db.Statement.Joins))\n\t\tfor _, join := range db.Statement.Joins {\n\t\t\tjoins = append(joins, join.Name)\n\t\t}\n\n\t\ttx := preloadDB(db, db.Statement.ReflectValue, db.Statement.Dest)\n\t\tif tx.Error != nil {\n\t\t\treturn\n\t\t}\n\n\t\tdb.AddError(preloadEntryPoint(tx, joins, &tx.Statement.Schema.Relationships, db.Statement.Preloads, db.Statement.Preloads[clause.Associations]))\n\t}\n}\n\nfunc AfterQuery(db *gorm.DB) {","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/go-gorm/gorm/blob/1d6ce99528060be18a42be09aca8d39efcb47f28/callbacks/query.go#L262-L298","documentation":"The Preload callback requires a parsed schema to resolve relation names. If db.Statement.Schema is nil when Statement.Preloads is non-empty, GORM adds fmt.Errorf(\"%w when using preload\", gorm.ErrModelValueRequired) - 'model value required when using preload'. This happens when the query was built without a model, most commonly via db.Table(...) or Raw SQL, because Table does not produce a schema.","triggerScenarios":"db.Table(\"users\").Preload(\"Orders\").Find(&users) - Table names the table but leaves Schema nil; or Preload chained onto a Session where the model was never set; Raw/SkipHooks flows that carry Preloads without a model.","commonSituations":"Migrating a query from db.Model(&User{}) to db.Table(\"users\") for performance/unmapped columns and forgetting to drop the Preload; generic repository helpers that accept table names; scoping code that clears the model.","solutions":["Use db.Model(&User{}) instead of db.Table(\"users\") when you need Preload.","Or drop the Preload call and load the related data with explicit queries.","For map destinations, Preload cannot work - switch to a typed model struct.","Add a guard in helpers: if len(preloads) > 0 && model == nil, panic/return early with a clear message."],"exampleFix":"// before\ndb.Table(\"users\").Preload(\"Orders\").Find(&users)\n\n// after\ndb.Model(&User{}).Preload(\"Orders\").Find(&users)","handlingStrategy":"validation","validationCode":"func canPreload(tx *gorm.DB) bool {\n    return tx.Statement != nil && tx.Statement.Schema != nil\n}\n// wrapper:\nif len(preloads) > 0 && !canPreload(db) {\n    return errors.New(\"Preload requires db.Model(&Struct{}), not Table/Raw\")\n}","typeGuard":null,"tryCatchPattern":"if err := db.Table(\"users\").Preload(\"Orders\").Find(&users).Error; err != nil {\n    if errors.Is(err, gorm.ErrModelValueRequired) {\n        // rebuild with db.Model(&User{}) and retry\n    }\n    return err\n}","preventionTips":["Never combine Table(...) or Raw with Preload - Preload needs a schema.","Centralize query building so the Model choice and preload list are set together."],"tags":["gorm","preload","model-required","api-misuse"],"backgroundTag":null,"analyzedSha":"1d6ce99528060be18a42be09aca8d39efcb47f28","analyzedAt":"2026-08-15T13:01:23.433Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}