geektutu/7days-golang · critical
panic(p)
Error message
panic(p)
What it means
This is not an error value but a re-panicked Go panic. In gee-orm, when code inside a transaction panics, the deferred recovery block first rolls the transaction back, then re-throws the original panic with panic(p) so the failure is not silently swallowed. You see it because your code (or the library's callback) panicked mid-transaction and the transaction was already rolled back before the panic propagated.
Source
Thrown at gee-orm/day7-migrate/geeorm.go:69
// NewSession creates a new session for next operations
func (engine *Engine) NewSession() *session.Session {
return session.New(engine.db, engine.dialect)
}
// TxFunc will be called between tx.Begin() and tx.Commit()
// https://stackoverflow.com/questions/16184238/database-sql-tx-detecting-commit-or-rollback
type TxFunc func(*session.Session) (interface{}, error)
// Transaction executes sql wrapped in a transaction, then automatically commit if no error occurs
func (engine *Engine) Transaction(f TxFunc) (result interface{}, err error) {
s := engine.NewSession()
if err := s.Begin(); err != nil {
return nil, err
}
defer func() {
if p := recover(); p != nil {
_ = s.Rollback()
panic(p) // re-throw panic after Rollback
} else if err != nil {
_ = s.Rollback() // err is non-nil; don't change it
} else {
err = s.Commit() // err is nil; if Commit returns error update err
}
}()
return f(s)
}
// difference returns a - b
func difference(a []string, b []string) (diff []string) {
mapB := make(map[string]bool)
for _, v := range b {
mapB[v] = true
}
for _, v := range a {
if _, ok := mapB[v]; !ok {View on GitHub (pinned to cf36443821)
Solutions
- Find the ORIGINAL panic value: look at the stack trace above this re-throw to locate the actual panicking code, since the defer at geeorm.go:69 only re-throws after Rollback.
- Fix the root cause in the code that ran inside the transaction (nil checks, bounds checks, safe type assertions).
- If you intentionally panic inside a transaction, recover it outside the geeorm.Transaction call instead.
- No data cleanup is needed: the library already called s.Rollback(), so the DB transaction was aborted correctly.
Example fix
// before: code inside transaction panics on nil map
func (u *UserMgr) Save(s *geeorm.Session) {
u.settings["a"] = 1 // panics if u.settings is nil
}
// after: initialize before use
func (u *UserMgr) Save(s *geeorm.Session) {
if u.settings == nil {
u.settings = map[string]interface{}{}
}
u.settings["a"] = 1
} Defensive patterns
Strategy: try-catch
Validate before calling
// Go: validate transaction inputs before entering geeorm.Transaction
if tx == nil || db == nil {
return fmt.Errorf("transaction requires non-nil db")
}
if err := validateRows(rows); err != nil {
return err
} Type guard
func nonNil[T any](v T, ok bool) bool { return ok && !isNil(v) }
// usage: if u.settings == nil { u.settings = map[string]any{} } Try / catch
// Go: recover around the transaction boundary so panics inside don't escape
func safeTx(db *geeorm.DB, fn func(s *geeorm.Session) error) (err error) {
defer func() {
if p := recover(); p != nil {
err = fmt.Errorf("transaction panicked: %v", p)
}
}()
_, err = db.Transaction(fn)
return err
} Prevention
- Never call panic() for expected error paths inside transactions; return errors instead.
- Initialize all maps/slices used inside transaction callbacks before calling geeorm.Transaction.
- Log recover()'d panic values at the boundary so the root cause is visible above the re-throw.
- Remember the library already rolls back on panic — don't add a second Rollback that can double-fire.
When it happens
Trigger: Any panic raised between geeorm.Transaction's Begin() and Commit()/Rollback() — e.g. a nil pointer dereference, index out of range, or an explicit panic inside the transaction callback/function passed to s (Session) operations.
Common situations: A nil map or nil pointer touched inside a transaction body; a user-supplied hook/OnUpdate callback that panics; unexpected type assertion failures on scanned columns during a migration or query within the transaction.
Related errors
- panic(p)
- invalid sql type %s (%s)
- invalid sql type %s (%s)
- invalid sql type %s (%s)
- invalid sql type %s (%s)
AI-assisted analysis of geektutu/7days-golang@cf36443821 (2026-09-03).
Data as JSON: /api/errors/470b36b79b9b4e9c.
Report an issue: GitHub.