MHSanaei/3x-ui · critical

sqlite integrity check failed: %s

Error message

sqlite integrity check failed: %s

What it means

The SQLite integrity check (PRAGMA integrity_check) returned something other than 'ok', meaning pages, indexes, or freelist structures in the .db file are damaged. The raw PRAGMA result string is appended (commonly a list like 'wrong # of entries in page N'), identifying which pages are corrupt. Typical root causes are power loss, a killed process mid-write without WAL, or a corrupted filesystem.

Source

Thrown at internal/database/db.go:2279

func ValidateSQLiteDB(dbPath string) error {
	if _, err := os.Stat(dbPath); err != nil {
		return err
	}
	gdb, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{Logger: logger.Discard})
	if err != nil {
		return err
	}
	sqlDB, err := gdb.DB()
	if err != nil {
		return err
	}
	defer sqlDB.Close()
	var res string
	if err := gdb.Raw("PRAGMA integrity_check;").Scan(&res).Error; err != nil {
		return err
	}
	if res != "ok" {
		return errors.New("sqlite integrity check failed: " + res)
	}
	return nil
}

View on GitHub (pinned to ad32144c42)

Solutions

  1. Stop x-ui, copy /etc/x-ui/x-ui.db aside, then try: sqlite3 x-ui.db '.recover' | sqlite3 fixed.db and swap the recovered file in
  2. If .recover fails, restore from the most recent BackupSQLite snapshot or .bak file next to the DB
  3. Enable WAL journal mode and adequate busy_timeout to reduce torn-write risk going forward
  4. If the damage is limited to traffic-stats indexes, deleting derived tables and letting jobs repopulate them may suffice — inspect the PRAGMA output first

Example fix

# before
# (panel reports integrity check failure on boot/health run)

# after
systemctl stop x-ui
cp /etc/x-ui/x-ui.db /etc/x-ui/x-ui.db.corrupt
sqlite3 /etc/x-ui/x-ui.db.corrupt '.recover' | sqlite3 /etc/x-ui/x-ui.db
systemctl start x-ui
Defensive patterns

Strategy: fallback

Try / catch

if err := checkIntegrity(dbPath); err != nil {
    log.Printf("integrity: %v — attempting .recover from last backup", err)
    if rerr := restoreFromBackup(dbPath); rerr != nil {
        log.Fatalf("unrecoverable: %v / %v", err, rerr)
    }
}

Prevention

When it happens

Trigger: Panel killed -9 during heavy traffic stats writes; disk full during a write; copying the .db file while a write is in flight; the check runs as part of a health/verify path in db.go around line 2279.

Common situations: VPS abrupt reboots; running the DB on network storage (NFS) that does not honor SQLite locking; restore from a truncated backup.

Related errors


AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15). Data as JSON: /api/errors/3465dfcef8ef411c. Report an issue: GitHub.