{"record":{"id":"0ef0169a3ebff1c6","repo":"geektutu/7days-golang","slug":"panic-p","errorCode":null,"errorMessage":"panic(p)","messagePattern":"panic\\(p\\)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"gee-orm/day6-transaction/geeorm.go","lineNumber":66,"sourceCode":"// NewSession creates a new session for next operations\nfunc (engine *Engine) NewSession() *session.Session {\n\treturn session.New(engine.db, engine.dialect)\n}\n\n// TxFunc will be called between tx.Begin() and tx.Commit()\n// https://stackoverflow.com/questions/16184238/database-sql-tx-detecting-commit-or-rollback\ntype TxFunc func(*session.Session) (interface{}, error)\n\n// Transaction executes sql wrapped in a transaction, then automatically commit if no error occurs\nfunc (engine *Engine) Transaction(f TxFunc) (result interface{}, err error) {\n\ts := engine.NewSession()\n\tif err := s.Begin(); err != nil {\n\t\treturn nil, err\n\t}\n\tdefer func() {\n\t\tif p := recover(); p != nil {\n\t\t\t_ = s.Rollback()\n\t\t\tpanic(p) // re-throw panic after Rollback\n\t\t} else if err != nil {\n\t\t\t_ = s.Rollback() // err is non-nil; don't change it\n\t\t} else {\n\t\t\terr = s.Commit() // err is nil; if Commit returns error update err\n\t\t}\n\t}()\n\n\treturn f(s)\n}\n","sourceCodeStart":48,"sourceCodeEnd":76,"githubUrl":"https://github.com/geektutu/7days-golang/blob/cf3644382101dc13e7fd92e8f5c66cabc51bcd3b/gee-orm/day6-transaction/geeorm.go#L48-L76","documentation":"In Transaction (day6-transaction), the deferred recover handler re-throws any panic (panic(p)) after rolling back the transaction. This is not an error the library invents — it preserves an original panic that occurred inside the transaction callback (e.g. an 'invalid sql type' schema panic or a nil-map panic) while guaranteeing Rollback ran first.","triggerScenarios":"Any panic raised inside the transaction's function body or its deferred chain: e.g. DataTypeOf panicking on an unsupported field type, a nil pointer in the callback, or Commit-side panics — all surface as this re-thrown panic after rollback.","commonSituations":"A schema bug (like error 107's invalid sql type) occurring mid-transaction; user callback code dividing by zero or indexing nil; bugs in hook code executed inside the transaction.","solutions":["Look at the original panic value/stack trace chained below this re-throw — the root cause is inside the transaction callback or the schema","Fix the underlying panic source (e.g. unsupported field type in the model)","If you need to convert panics to errors, wrap the s.Transaction call in your own recover at the caller level"],"exampleFix":"// before\n_ = db.Transaction(func(s *geeorm.Session) error {\n    return s.Raw(...).Find(&users) // may panic on bad schema\n})\n// after\nfunc safeTx(db *geeorm.Engine) (err error) {\n    defer func() { if p := recover(); p != nil { err = fmt.Errorf(\"tx panic: %v\", p) } }()\n    return db.Transaction(func(s *geeorm.Session) error {\n        return s.Raw(...).Find(&users)\n    })\n}","handlingStrategy":"try-catch","validationCode":"// ensure the model is schema-valid before entering the transaction\nif err := checkSchemaTypes(&Order{}); err != nil {\n    return err\n}\nreturn db.Transaction(func(s *geeorm.Session) error { ... })","typeGuard":null,"tryCatchPattern":"func runTx(db *geeorm.Engine) (err error) {\n    defer func() {\n        if p := recover(); p != nil {\n            err = fmt.Errorf(\"transaction panicked (rolled back): %v\", p)\n        }\n    }()\n    return db.Transaction(func(s *geeorm.Session) error {\n        // transaction body\n        return nil\n    })\n}","preventionTips":["Treat the re-thrown panic as the original panic — read its stack, the bug is in your callback or schema","Validate model schemas before opening transactions","Keep transaction callbacks free of code that can panic (bounds checks, nil checks)"],"tags":["go","panic","transaction","rollback","orm"],"backgroundTag":"panic-rethrow-after-rollback","analyzedSha":"cf3644382101dc13e7fd92e8f5c66cabc51bcd3b","analyzedAt":"2026-09-03T18:31:24.087Z","contentChangedAt":"2026-09-03T18:31:24.087Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}