MHSanaei/3x-ui · warning
sqlite backup is unavailable for PostgreSQL
Error message
sqlite backup is unavailable for PostgreSQL
What it means
BackupSQLite guards at the top with IsPostgres() and refuses to run when the panel is booted against PostgreSQL, because there is no SQLite file to back up — the logical database lives in Postgres. It is a deliberate fail-fast guard, not a corruption signal. Callers that offer a 'backup database' button should hide or re-route it when Postgres is active.
Source
Thrown at internal/database/db.go:2182
}
func IsNotFound(err error) bool {
return errors.Is(err, gorm.ErrRecordNotFound)
}
func IsSQLiteDB(file io.ReaderAt) (bool, error) {
signature := []byte("SQLite format 3\x00")
buf := make([]byte, len(signature))
_, err := file.ReadAt(buf, 0)
if err != nil {
return false, err
}
return bytes.Equal(buf, signature), nil
}
func BackupSQLite(dstPath string) (err error) {
if IsPostgres() {
return errors.New("sqlite backup is unavailable for PostgreSQL")
}
if db == nil {
return errors.New("database is not initialized")
}
if _, err := os.Lstat(dstPath); err == nil {
return fmt.Errorf("sqlite backup destination already exists: %s", dstPath)
} else if !errors.Is(err, os.ErrNotExist) {
return err
}
defer func() {
if err != nil {
_ = os.Remove(dstPath)
}
}()
ctx, cancel := context.WithTimeout(context.Background(), backupSQLiteTimeout)
defer cancel()
View on GitHub (pinned to ad32144c42)
Solutions
- Use a Postgres-native backup instead: pg_dump against the DSN in XUI_DB_DSN
- If code calls BackupSQLite, branch on database.IsPostgres() first and export via ExportPostgresToSQLite if a .db file is genuinely wanted
- Remove or condition scheduled backup jobs that assume SQLite
Example fix
// before
err := database.BackackSQLite(dst) // typo aside, called unconditionally
// after
if database.IsPostgres() {
return fmt.Errorf("use pg_dump; sqlite backup unavailable under postgres")
}
err := database.BackupSQLite(dst) Defensive patterns
Strategy: validation
Validate before calling
if database.IsPostgres() {
return errors.New("skip sqlite backup: panel runs postgres; use pg_dump")
}
return database.BackupSQLite(dst) Try / catch
if err := database.BackupSQLite(dst); err != nil {
if strings.Contains(err.Error(), "unavailable for PostgreSQL") {
// route to pg_dump instead of failing the backup job
}
} Prevention
- Branch backup tooling on database.IsPostgres() after any DB migration
- For Postgres, schedule pg_dump rather than the panel's SQLite path
When it happens
Trigger: Invoking the backup endpoint (panel settings backup or CLI path that calls database.BackupSQLite) while XUI_DB_TYPE=postgres; a cron or script written against SQLite that survived a migration to Postgres.
Common situations: After migrating SQLite→Postgres the admin still clicks the old backup button; automation scripts calling the backup API unchanged post-migration.
Related errors
- database is not initialized
- traffic writer queue full
- sqlite backup destination already exists: %s
- source sqlite not found at %s: %w
- copy %T: %w
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/ecf76b880774bce7.
Report an issue: GitHub.