MHSanaei/3x-ui · error
source DSN is required
Error message
source DSN is required
What it means
ExportPostgresToSQLite (Postgres→SQLite export, the reverse of MigrateData) requires a non-empty srcDSN and fails fast otherwise. Unlike the SQLite→Postgres direction, the source DSN is a parameter rather than the process env, so passing '' means there is no Postgres to read from. The destination file is removed/recreated, so the guard runs before any destructive step.
Source
Thrown at internal/database/migrate_data.go:158
// setval is never rolled back by PostgreSQL, so sequences are resynced only
// after the transaction has committed.
if err := resetPostgresSequences(dst); err != nil {
log.Printf("warning: failed to reset some postgres sequences: %v", err)
}
log.Printf("Migration complete: %d rows across %d tables.", totalRows, len(migrationModels()))
log.Println("Set XUI_DB_TYPE=postgres and XUI_DB_DSN=... in /etc/default/x-ui, then restart x-ui.")
return nil
}
// ExportPostgresToSQLite copies every row from the PostgreSQL database described
// by srcDSN into a fresh SQLite file at dstPath. It is the reverse of
// MigrateData and is used to hand a PostgreSQL-backed panel a portable .db file.
// dstPath is created/overwritten; the PostgreSQL source is left untouched.
func ExportPostgresToSQLite(srcDSN, dstPath string) error {
if srcDSN == "" {
return errors.New("source DSN is required")
}
if err := os.MkdirAll(path.Dir(dstPath), 0o755); err != nil {
return err
}
// Start from an empty file so AutoMigrate creates the canonical schema.
if err := os.Remove(dstPath); err != nil && !os.IsNotExist(err) {
return err
}
src, err := gorm.Open(postgres.Open(srcDSN), &gorm.Config{Logger: logger.Discard})
if err != nil {
return fmt.Errorf("open postgres source: %w", err)
}
srcSQL, err := src.DB()
if err != nil {
return err
}
defer srcSQL.Close()View on GitHub (pinned to ad32144c42)
Solutions
- Pass the same DSN used for XUI_DB_DSN as srcDSN
- If scripting, default it explicitly: srcDSN := os.Getenv("XUI_DB_DSN") and fail with a clear message if empty
- Verify connectivity with psql '<dsn>' -c 'select 1' before exporting
Example fix
// before
err := database.ExportPostgresToSQLite("", dstPath)
// after
dsn := os.Getenv("XUI_DB_DSN")
if dsn == "" { log.Fatal("XUI_DB_DSN required for export") }
err := database.ExportPostgresToSQLite(dsn, dstPath) Defensive patterns
Strategy: validation
Validate before calling
dsn := os.Getenv("XUI_DB_DSN")
if dsn == "" {
log.Fatal("XUI_DB_DSN must be set for postgres export")
} Try / catch
if err := database.ExportPostgresToSQLite(dsn, dst); err != nil {
if strings.Contains(err.Error(), "source DSN is required") {
log.Fatal("provide the postgres DSN as the first argument")
}
return err
} Prevention
- Default srcDSN from XUI_DB_DSN and validate non-empty before calling
- Ensure the env var is present in systemd units / cron shells that run exports
When it happens
Trigger: Calling ExportPostgresToSQLite programmatically with an empty first argument; a CLI wrapper that resolves the DSN from env but the env var is unset in that shell.
Common situations: Handing a Postgres-backed panel a portable .db file; downgrading back to SQLite; scripts run under systemd where the DSN env var is missing from the unit.
Related errors
- destination DSN is required
- XUI_DB_TYPE=postgres but XUI_DB_DSN is empty
- source sqlite not found at %s: %w
- open sqlite source: %w
- open postgres destination: %w
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/9b8d2e0608bc25b3.
Report an issue: GitHub.