Quellcode durchsuchen

fix: ignore duplicate column errors during AutoMigrate on upgraded DBs

SQLite raises 'duplicate column name: <col>' when GORM tries to ADD a
column that already exists in an older schema (seen: allow_private_address,
node_id on the nodes table). This caused database initialisation to fail on
every restart after an upgrade.

The new isIgnorableDuplicateColumnErr helper skips the error only when:
  1. The error message matches 'duplicate column name: <col>'
  2. Migrator().HasColumn confirms the column is already present in the DB

Fresh databases and all other error types are unaffected.
MHSanaei vor 20 Stunden
Ursprung
Commit
bd8d33980f
1 geänderte Dateien mit 28 neuen und 2 gelöschten Zeilen
  1. 28 2
      database/db.go

+ 28 - 2
database/db.go

@@ -10,6 +10,7 @@ import (
 	"os"
 	"os"
 	"path"
 	"path"
 	"slices"
 	"slices"
+	"strings"
 	"time"
 	"time"
 
 
 	"github.com/mhsanaei/3x-ui/v3/config"
 	"github.com/mhsanaei/3x-ui/v3/config"
@@ -42,8 +43,12 @@ func initModels() error {
 		&model.Node{},
 		&model.Node{},
 		&model.ApiToken{},
 		&model.ApiToken{},
 	}
 	}
-	for _, model := range models {
-		if err := db.AutoMigrate(model); err != nil {
+	for _, mdl := range models {
+		if err := db.AutoMigrate(mdl); err != nil {
+			if isIgnorableDuplicateColumnErr(err, mdl) {
+				log.Printf("Ignoring duplicate column during auto migration for %T: %v", mdl, err)
+				continue
+			}
 			log.Printf("Error auto migrating model: %v", err)
 			log.Printf("Error auto migrating model: %v", err)
 			return err
 			return err
 		}
 		}
@@ -51,6 +56,27 @@ func initModels() error {
 	return nil
 	return nil
 }
 }
 
 
+func isIgnorableDuplicateColumnErr(err error, mdl any) bool {
+	if err == nil {
+		return false
+	}
+	errMsg := strings.ToLower(err.Error())
+	const dupPrefix = "duplicate column name:"
+	if !strings.Contains(errMsg, dupPrefix) {
+		return false
+	}
+	idx := strings.Index(errMsg, dupPrefix)
+	if idx < 0 {
+		return false
+	}
+	col := strings.TrimSpace(errMsg[idx+len(dupPrefix):])
+	col = strings.Trim(col, "`\"[]")
+	if col == "" {
+		return false
+	}
+	return db != nil && db.Migrator().HasColumn(mdl, col)
+}
+
 // initUser creates a default admin user if the users table is empty.
 // initUser creates a default admin user if the users table is empty.
 func initUser() error {
 func initUser() error {
 	empty, err := isTableEmpty("users")
 	empty, err := isTableEmpty("users")