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
- 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
- If .recover fails, restore from the most recent BackupSQLite snapshot or .bak file next to the DB
- Enable WAL journal mode and adequate busy_timeout to reduce torn-write risk going forward
- 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
- Keep WAL journal mode and regular BackupSQLite snapshots enabled
- Avoid killing the panel mid-write; use graceful stop
- Never place the SQLite file on NFS or unjournaled filesystems
- Test restores so the recovery path is known before corruption hits
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
- restore failed: %w
- open sqlite source: %w
- sqlite backup is unavailable for PostgreSQL
- database is not initialized
- traffic writer queue full
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/3465dfcef8ef411c.
Report an issue: GitHub.