MHSanaei/3x-ui · error
destination DSN is required
Error message
destination DSN is required
What it means
MigrateData (SQLite→Postgres migration) requires a non-empty destination DSN and rejects the call before touching either database when dstDSN is ''. It is the symmetric guard to the XUI_DB_TYPE check: copying rows into 'no database' is meaningless. The source file at srcPath must also exist (checked immediately before).
Source
Thrown at internal/database/migrate_data.go:72
&model.Host{},
&model.NodeClientTraffic{},
&model.NodeClientIp{},
&model.ClientGlobalTraffic{},
&model.OutboundSubscription{},
}
}
// MigrateData copies every row from the configured SQLite file at srcPath into
// a fresh PostgreSQL database described by dstDSN. The destination tables are
// (re)created with AutoMigrate; truncate and copy then run in one transaction,
// so a failed migration leaves the destination data unchanged. Source data is
// left untouched.
func MigrateData(srcPath, dstDSN string) error {
if _, err := os.Stat(srcPath); err != nil {
return fmt.Errorf("source sqlite not found at %s: %w", srcPath, err)
}
if dstDSN == "" {
return errors.New("destination DSN is required")
}
if err := os.MkdirAll(path.Dir(srcPath), 0o755); err != nil {
return err
}
srcDSN := srcPath + "?_journal_mode=WAL&_busy_timeout=10000"
src, err := gorm.Open(sqlite.Open(srcDSN), &gorm.Config{Logger: logger.Discard})
if err != nil {
return fmt.Errorf("open sqlite source: %w", err)
}
srcSQL, err := src.DB()
if err != nil {
return err
}
defer srcSQL.Close()
dst, err := gorm.Open(postgres.Open(dstDSN), &gorm.Config{Logger: logger.Discard})View on GitHub (pinned to ad32144c42)
Solutions
- Pass a valid Postgres DSN: ./x-ui migrate-db --dst 'postgres://user:pass@host:5432/xui?sslmode=disable' (or set the env var your wrapper reads)
- Confirm the source path exists at the reported location before retrying
- Echo the variable before running if a script builds the flag dynamically
Example fix
# before ./x-ui migrate --src /etc/x-ui/x-ui.db --dst "" # after ./x-ui migrate --src /etc/x-ui/x-ui.db --dst "postgres://xui:pass@10.0.0.5:5432/xui"
Defensive patterns
Strategy: validation
Validate before calling
if dstDSN == "" {
return errors.New("pass the postgres DSN, e.g. postgres://user:pass@host:5432/xui")
} Try / catch
if err := database.MigrateData(src, dst); err != nil {
if strings.Contains(err.Error(), "destination DSN is required") {
// fix invocation, not data: prompt for DSN and re-run
}
return err
} Prevention
- Require the DSN flag in migration scripts (fail on empty) before calling MigrateData
- Dry-run psql connectivity with the same DSN first
When it happens
Trigger: Running the migration CLI/endpoint with the --dst flag omitted or an empty string; a wrapper script that reads the DSN from an unset env var and passes '' through.
Common situations: First-time migration to Postgres where the operator forgets to export the DSN variable the script expects; shell quoting mistakes that expand to empty.
Related errors
- XUI_DB_TYPE=postgres but XUI_DB_DSN is empty
- source DSN is required
- source sqlite not found at %s: %w
- open postgres destination: %w
- AutoMigrate %T: %w
AI-assisted analysis of MHSanaei/3x-ui@ad32144c42 (2026-08-15).
Data as JSON: /api/errors/77085485c8143dde.
Report an issue: GitHub.