juanfont/headscale · critical

adding description to pre_auth_keys: %w

Error message

adding description to pre_auth_keys: %w

What it means

Migration '202606191501-pre-auth-key-description' fails adding the free-text description column to pre_auth_keys (HasColumn-guarded AddColumn) for the v2 keys API. Identical failure class to the other AddColumn migrations: ALTER privilege missing, database locked, disk full, or drifted schema confusing the guard.

Source

Thrown at hscontrol/db/db.go:809

						err := tx.Migrator().AddColumn(&types.APIKey{}, "user_id")
						if err != nil {
							return fmt.Errorf("adding user_id to api_keys: %w", err)
						}
					}

					return nil
				},
				Rollback: func(db *gorm.DB) error { return nil },
			},
			{
				// Add a free-text description to pre-auth keys, set via the
				// v2 keys API.
				ID: "202606191501-pre-auth-key-description",
				Migrate: func(tx *gorm.DB) error {
					if !tx.Migrator().HasColumn(&types.PreAuthKey{}, "description") {
						err := tx.Migrator().AddColumn(&types.PreAuthKey{}, "description")
						if err != nil {
							return fmt.Errorf("adding description to pre_auth_keys: %w", err)
						}
					}

					return nil
				},
				Rollback: func(db *gorm.DB) error { return nil },
			},
			{
				// Add a revoked timestamp to pre-auth keys. The v2 API's DELETE
				// soft-revokes a key (set revoked = now) rather than destroying
				// it; the row is reaped later by the background collector.
				ID: "202606201200-pre-auth-key-revoked",
				Migrate: func(tx *gorm.DB) error {
					if !tx.Migrator().HasColumn(&types.PreAuthKey{}, "revoked") {
						err := tx.Migrator().AddColumn(&types.PreAuthKey{}, "revoked")
						if err != nil {
							return fmt.Errorf("adding revoked to pre_auth_keys: %w", err)
						}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Resolve the wrapped underlying error (privileges / locks / disk)
  2. Pre-apply ALTER TABLE pre_auth_keys ADD COLUMN description text DEFAULT '' if drift makes AddColumn fail, then restart - the HasColumn guard makes re-runs safe
  3. Confirm the column post-startup with \d pre_auth_keys or PRAGMA table_info(pre_auth_keys)
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the database accepts DDL before the upgrade window
if _, err := db.Exec("CREATE TEMP TABLE _p(id integer)"); err != nil {
	log.Fatalf("database not DDL-writable: %v", err)
}

Prevention

When it happens

Trigger: Startup migration on a schema without pre_auth_keys.description while DDL execution is blocked or unauthorized.

Common situations: Upgrading alongside the v2 API rollout; constrained DB roles; shared SQLite databases; read-only database mounts.

Related errors


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