MHSanaei/3x-ui · critical
XUI_DB_TYPE=postgres but XUI_DB_DSN is empty
Error message
XUI_DB_TYPE=postgres but XUI_DB_DSN is empty
What it means
InitDB refuses to continue when config.GetDBKind() returns 'postgres' but the DSN environment variable XUI_DB_DSN is empty. PostgreSQL has no default DSN in this codebase, so there is nothing to connect to; failing fast prevents GORM from attempting a meaningless connection loop. This is a startup-time configuration validation error.
Source
Thrown at internal/database/db.go:1986
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: time.Second,
LogLevel: logger.Info,
IgnoreRecordNotFoundError: true,
Colorful: true,
},
)
} else {
gormLogger = logger.Discard
}
c := &gorm.Config{Logger: gormLogger, DisableForeignKeyConstraintWhenMigrating: true}
var err error
switch config.GetDBKind() {
case "postgres":
dsn := config.GetDBDSN()
if dsn == "" {
return errors.New("XUI_DB_TYPE=postgres but XUI_DB_DSN is empty")
}
db, err = openPostgresWithRetry(dsn, c)
if err != nil {
return err
}
default:
dir := path.Dir(dbPath)
if err = os.MkdirAll(dir, 0o755); err != nil {
return err
}
if err = cleanupSQLiteBackupDirs(filepath.Dir(dbPath)); err != nil {
log.Printf("clean SQLite backup directories: %v", err)
}
sync := sqliteSynchronous()
journal := sqliteJournalMode()
dsn := dbPath + "?_journal_mode=" + journal + "&_busy_timeout=10000&_synchronous=" + sync + "&_txlock=immediate"
db, err = gorm.Open(sqlite.Open(dsn), c)View on GitHub (pinned to ad32144c42)
Solutions
- Set XUI_DB_DSN to a full libpq/pq URL, e.g. postgres://user:pass@host:5432/xui?sslmode=disable
- Verify with: XUI_DB_TYPE=postgres XUI_DB_DSN=... ./x-ui migrate-db or just restart the service
- If Postgres was not intended, unset XUI_DB_TYPE to fall back to SQLite at /etc/x-ui/x-ui.db
Example fix
# before XUI_DB_TYPE=postgres # after XUI_DB_TYPE=postgres XUI_DB_DSN=postgres://xui:secret@db.internal:5432/xui?sslmode=require
Defensive patterns
Strategy: validation
Validate before calling
if os.Getenv("XUI_DB_TYPE") == "postgres" && os.Getenv("XUI_DB_DSN") == "" {
log.Fatal("XUI_DB_DSN is required when XUI_DB_TYPE=postgres")
} Try / catch
if err := database.InitDB(dbPath); err != nil {
if strings.Contains(err.Error(), "XUI_DB_DSN is empty") {
log.Fatal("set XUI_DB_DSN, e.g. postgres://user:pass@host:5432/xui")
}
log.Fatal(err)
} Prevention
- Set XUI_DB_TYPE and XUI_DB_DSN together in /etc/default/x-ui
- Add a preflight check in deploy scripts that fails when type=postgres and DSN is unset
- Test the DSN with psql before starting the panel
When it happens
Trigger: Setting XUI_DB_TYPE=postgres without XUI_DB_DSN in /etc/default/x-ui (or the systemd unit env); typo'ing the DSN variable name; exporting XUI_DB_TYPE in a shell but forgetting the DSN when running ./x-ui or the migration subcommand.
Common situations: Migrating a panel from SQLite to Postgres per the documented flow; CI jobs that set only the DB type; docker deployments missing the -e XUI_DB_DSN flag.
Related errors
- destination DSN is required
- postgres unreachable after %d attempts: %w
- sqlite backup is unavailable for PostgreSQL
- source DSN is required
- traffic writer queue full
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/0478388ad9ffd6ec.
Report an issue: GitHub.