AdguardTeam/AdGuardHome · error

loading sessions

Error message

loading sessions: %w

What it means

The default session storage constructor failed while loading persisted web-user sessions from the bbolt database file. This wraps the concrete failure from loadSessions (transaction start, iteration, or commit).

Solutions

  1. Inspect the wrapped error to identify the failing phase (transaction/iterate/commit)
  2. If the file is corrupt, stop the service, back up and delete/recreate sessions.db (users must re-login)
  3. Ensure only one instance of the service accesses the sessions database file
  4. Check file permissions on the sessions db path for the service user

Example fix

# before
# corrupted sessions.db blocks startup
# after
mv /var/lib/app/sessions.db /var/lib/app/sessions.db.bak
# restart; users re-authenticate
Defensive patterns

Strategy: try-catch

Validate before calling

f, err := os.OpenFile(sessionsPath, os.O_RDWR, 0o600)
if err != nil { return fmt.Errorf("sessions db unusable: %w", err) }
f.Close()

Try / catch

ds, err := aghuser.NewDefaultSessionStorage(ctx, logger, path)
if err != nil {
    if strings.Contains(err.Error(), "loading sessions") { back up & reset the sessions file }
}

Prevention

When it happens

Trigger: Calling NewDefaultSessionStorage on a bbolt file that cannot be read or processed: corrupted database, a database created by an incompatible schema/version, or a file the process cannot lock.

Common situations: Upgrading the application across a session-store schema change without migration; a bbolt file truncated by an unclean shutdown; another process holding a flock on the same sessions.db.

Related errors


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

Appendix: source

Thrown at internal/aghuser/sessionstorage.go:128

	dbFilename := conf.DBPath
	ds.db, err = bbolt.Open(dbFilename, aghos.DefaultPermFile, &bbolt.Options{
		Timeout: dbOpenTimeout,
		Logger:  newBBoltLogger(ctx, ds.logger),
	})
	if err != nil {
		ds.logger.ErrorContext(ctx, "opening db", "filename", dbFilename, slogutil.KeyError, err)
		if errors.Is(err, berrors.ErrInvalid) {
			const s = "AdGuard Home cannot be initialized due to an incompatible file system.\n" +
				"Please read the explanation here: https://adguard-dns.io/kb/adguard-home/getting-started/#limitations"
			slogutil.PrintLines(ctx, ds.logger, slog.LevelError, "", s)
		}

		return nil, err
	}

	err = ds.loadSessions(ctx)
	if err != nil {
		return nil, fmt.Errorf("loading sessions: %w", err)
	}

	return ds, nil
}

// newBBoltLogger returns a new [*bbolt.DefaultLogger] that logs messages using
// the given [slog.Logger].  l must not be nil.
func newBBoltLogger(ctx context.Context, l *slog.Logger) (bl *bbolt.DefaultLogger) {
	bl = &bbolt.DefaultLogger{
		Logger: slog.NewLogLogger(l.Handler(), slog.LevelDebug),
	}

	if l.Enabled(ctx, slog.LevelDebug) {
		bl.EnableDebug()
	}

	return bl
}

View on GitHub (pinned to b41aefbe51)