{"record":{"id":"627c6d0bcc4a2ecd","repo":"juanfont/headscale","slug":"automigrating-types-preauthkey-w","errorCode":null,"errorMessage":"automigrating types.PreAuthKey: %w","messagePattern":"automigrating types\\.PreAuthKey: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hscontrol/db/db.go","lineNumber":111,"sourceCode":"\t\t\t\t\t}\n\n\t\t\t\t\terr := tx.AutoMigrate(&types.Route{}) //nolint:staticcheck // SA1019: Route kept for migrations\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"automigrating types.Route: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tRollback: func(db *gorm.DB) error { return nil },\n\t\t\t},\n\t\t\t// Add back constraint so you cannot delete preauth keys that\n\t\t\t// is still used by a node.\n\t\t\t{\n\t\t\t\tID: \"202501311657\",\n\t\t\t\tMigrate: func(tx *gorm.DB) error {\n\t\t\t\t\terr := tx.AutoMigrate(&types.PreAuthKey{})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"automigrating types.PreAuthKey: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\terr = tx.AutoMigrate(&types.Node{})\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"automigrating types.Node: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tRollback: func(db *gorm.DB) error { return nil },\n\t\t\t},\n\t\t\t// Ensure there are no nodes referring to a deleted preauthkey.\n\t\t\t{\n\t\t\t\tID: \"202502070949\",\n\t\t\t\tMigrate: func(tx *gorm.DB) error {\n\t\t\t\t\tif tx.Migrator().HasTable(&types.PreAuthKey{}) {\n\t\t\t\t\t\terr := tx.Exec(`\nUPDATE nodes","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/db/db.go#L93-L129","documentation":"Migration 202501311657 failed at tx.AutoMigrate(&types.PreAuthKey{}), which re-adds the foreign-key constraint preventing deletion of pre-auth keys still referenced by nodes. Failure means GORM could not alter the pre_auth_keys table - typically a lock, permission, or constraint-cascade problem.","triggerScenarios":"Running migration 202501311657 on a Postgres database where another session holds a lock on pre_auth_keys, a SQLite file that is read-only, or a schema where re-adding the FK would immediately fail (e.g. existing orphan rows violating the constraint on strict configurations).","commonSituations":"Server restart while old instance still draining; NFS-mounted SQLite file; Postgres migration role without REFERENCES/ALTER privileges.","solutions":["Stop all other headscale/CLI processes touching the database and retry startup.","For Postgres: check pg_locks / pg_stat_activity for blocking sessions on pre_auth_keys.","Verify file permissions and write access on the SQLite database directory.","Restore from backup if the migration partially applied (gormigrate records applied IDs)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := db.NewHeadscaleDatabase(cfg); err != nil {\n    if strings.Contains(err.Error(), \"automigrating types.PreAuthKey\") {\n        // check pg_locks / SQLite lock holders, then restart\n    }\n}","preventionTips":["Stop all headscale processes before upgrading.","For Postgres, ensure the migration user owns or has ALTER rights on pre_auth_keys and nodes.","Keep databases on local disks, not NFS, when using SQLite."],"tags":["database","migration","gorm","preauth-key","foreign-key"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}