SigNoz/signoz · error
internal
internal
Error message
cannot begin transaction
What it means
RunInTxCtx is the generic transactional helper: when already inside a tx it just invokes the callback, otherwise it begins a new one with BeginTx. This error means a new transaction could not be started — connection acquisition failed, the context is invalid/canceled, or the DB is unavailable/read-only.
Source
Thrown at pkg/sqlstore/bun.go:40
db := bun.NewDB(sqldb, dialect, opts...)
for _, hook := range hooks {
db.AddQueryHook(hook)
}
return &BunDB{db, settings}
}
func (db *BunDB) RunInTxCtx(ctx context.Context, opts *sql.TxOptions, cb func(ctx context.Context) error) error {
tx, ok := txFromContext(ctx)
if ok {
return cb(ctx)
}
// begin transaction
tx, err := db.BeginTx(ctx, opts)
if err != nil {
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "cannot begin transaction")
}
defer func() {
if err := tx.Rollback(); err != nil {
if err != sql.ErrTxDone {
db.settings.Logger().ErrorContext(ctx, "cannot rollback transaction", errors.Attr(err))
}
}
}()
if err := cb(newContextWithTx(ctx, tx)); err != nil {
return err
}
return tx.Commit()
}
func (db *BunDB) BunDBCtx(ctx context.Context) bun.IDB {View on GitHub (pinned to 5069bf80b0)
Solutions
- Inspect wrapped error: context.Canceled vs too many connections vs bad conn
- Tune pool (max open conns, max idle, conn max lifetime) and check for tx leaks
- Retry with backoff for transient unavailability
- Point the service at a writable primary, not a read replica
Example fix
// before
err := sqlstore.RunInTxCtx(ctx, func(ctx context.Context) error { ... })
// after
err := retry.Do(func() error {
return sqlstore.RunInTxCtx(ctx, func(ctx context.Context) error { ... })
}, retry.Attempts(3), retry.RetryIf(isTransientConnErr)) Defensive patterns
Strategy: retry
Validate before calling
if ctx.Err() != nil { return ctx.Err() }
if err := db.PingContext(ctx); err != nil { return err } Type guard
func isBeginTxFailure(err error) bool {
return err != nil && strings.Contains(err.Error(), "cannot begin transaction")
} Try / catch
err := sqlstore.RunInTxCtx(ctx, cb)
if isBeginTxFailure(err) && isTransientDBErr(errors.Unwrap(err)) {
time.Sleep(250*time.Millisecond)
err = sqlstore.RunInTxCtx(ctx, cb)
} Prevention
- Tune pool max connections/lifetime; watch for tx leaks
- Write callbacks idempotent so retries are safe
- Target writable primaries, not read replicas
When it happens
Trigger: Calling RunInTxCtx (not nested) when the pool has no available connections, ctx is canceled, the DB is restarting, or max connection limits are hit server-side.
Common situations: Pool saturation from leaked/long transactions, Postgres max_connections exceeded, failover in progress, canceled parent contexts (HTTP client disconnects), read-only replicas targeted by mistake.
Related errors
- internal
- internal
- couldn't create cloud integration service account: %w
- failed to update deploy status
- couldn't get attribute keys: %w
AI-assisted analysis of SigNoz/signoz@5069bf80b0 (2026-08-28).
Data as JSON: /api/errors/a3d9855ab03d62e9.
Report an issue: GitHub.