AdguardTeam/AdGuardHome · error

opening transaction: %w

Error message

opening transaction: %w

What it means

StatsCtx.Close attempts to flush the current unit to the database and fails at db.Begin(true); the error is wrapped as 'opening transaction'.

Source

Thrown at internal/stats/stats.go:269

	defer func() {
		cerr := db.Close()
		if cerr == nil {
			s.logger.Debug("database closed")
		}

		err = errors.WithDeferred(err, cerr)
	}()

	// NOTE:  This mutex, when combined with the database transaction, is
	// required to be locked first.
	s.currMu.RLock()
	defer s.currMu.RUnlock()

	udb := s.curr.serialize()

	tx, err := db.Begin(true)
	if err != nil {
		return fmt.Errorf("opening transaction: %w", err)
	}
	defer func() { err = errors.WithDeferred(err, finishTxn(tx, err == nil)) }()

	return s.flushUnitToDB(udb, tx, s.curr.id)
}

// Update implements the [Interface] interface for *StatsCtx.  e must not be
// nil.
func (s *StatsCtx) Update(e *Entry) {
	s.confMu.Lock()
	defer s.confMu.Unlock()

	if !s.enabled || s.limit == 0 {
		return
	}

	err := e.validate()
	if err != nil {

View on GitHub (pinned to b41aefbe51)

Solutions

  1. Ensure Close is called exactly once (sync.Once or guard flag)
  2. Avoid concurrent transactions with Close; serialize access
  3. Check filesystem health/disk space before shutdown
Defensive patterns

Strategy: try-catch

Try / catch

var once sync.Once
once.Do(func() { closeErr = s.Close() })

Prevention

When it happens

Trigger: Calling Close when the bbolt database is already closed, locked by another process, or on a read-only/full disk at shutdown time.

Common situations: Double Close, closing while another goroutine holds a transaction, shutdown races, or the DB file deleted/permissions changed while running.

Related errors


AI-assisted analysis of AdguardTeam/AdGuardHome@b41aefbe51 (2026-08-27). Data as JSON: /api/errors/e3cf9f624ed263ec. Report an issue: GitHub.