juanfont/headscale · critical

automigrating types.PreAuthKey: %w

Error message

automigrating types.PreAuthKey: %w

What it means

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.

Source

Thrown at hscontrol/db/db.go:111

					}

					err := tx.AutoMigrate(&types.Route{}) //nolint:staticcheck // SA1019: Route kept for migrations
					if err != nil {
						return fmt.Errorf("automigrating types.Route: %w", err)
					}

					return nil
				},
				Rollback: func(db *gorm.DB) error { return nil },
			},
			// Add back constraint so you cannot delete preauth keys that
			// is still used by a node.
			{
				ID: "202501311657",
				Migrate: func(tx *gorm.DB) error {
					err := tx.AutoMigrate(&types.PreAuthKey{})
					if err != nil {
						return fmt.Errorf("automigrating types.PreAuthKey: %w", err)
					}

					err = tx.AutoMigrate(&types.Node{})
					if err != nil {
						return fmt.Errorf("automigrating types.Node: %w", err)
					}

					return nil
				},
				Rollback: func(db *gorm.DB) error { return nil },
			},
			// Ensure there are no nodes referring to a deleted preauthkey.
			{
				ID: "202502070949",
				Migrate: func(tx *gorm.DB) error {
					if tx.Migrator().HasTable(&types.PreAuthKey{}) {
						err := tx.Exec(`
UPDATE nodes

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Stop all other headscale/CLI processes touching the database and retry startup.
  2. For Postgres: check pg_locks / pg_stat_activity for blocking sessions on pre_auth_keys.
  3. Verify file permissions and write access on the SQLite database directory.
  4. Restore from backup if the migration partially applied (gormigrate records applied IDs).
Defensive patterns

Strategy: try-catch

Try / catch

if _, err := db.NewHeadscaleDatabase(cfg); err != nil {
    if strings.Contains(err.Error(), "automigrating types.PreAuthKey") {
        // check pg_locks / SQLite lock holders, then restart
    }
}

Prevention

When it happens

Trigger: 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).

Common situations: Server restart while old instance still draining; NFS-mounted SQLite file; Postgres migration role without REFERENCES/ALTER privileges.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/627c6d0bcc4a2ecd. Report an issue: GitHub.