juanfont/headscale · critical

adding column types.Node: %w

Error message

adding column types.Node: %w

What it means

Migration 202502131714 (moving routes from the routes table into nodes.approved_routes) failed adding the approved_routes column to nodes. DDL failure at this step is environmental: lock contention, missing ALTER privilege, insufficient disk for SQLite's table rewrite, or the column existing with an incompatible type (guarded by HasColumn, so re-runs are safe).

Source

Thrown at hscontrol/db/db.go:154

						if err != nil {
							return fmt.Errorf("setting auth_key to null on nodes with non-existing keys: %w", err)
						}
					}

					return nil
				},
				Rollback: func(db *gorm.DB) error { return nil },
			},
			// v0.26.0
			// Migrate all routes from the Route table to the new field ApprovedRoutes
			// in the Node table. Then drop the Route table.
			{
				ID: "202502131714",
				Migrate: func(tx *gorm.DB) error {
					if !tx.Migrator().HasColumn(&types.Node{}, "approved_routes") {
						err := tx.Migrator().AddColumn(&types.Node{}, "approved_routes")
						if err != nil {
							return fmt.Errorf("adding column types.Node: %w", err)
						}
					}

					nodeRoutes := map[uint64][]netip.Prefix{}

					var routes []types.Route //nolint:staticcheck // SA1019: Route kept for migrations

					err = tx.Find(&routes).Error
					if err != nil {
						return fmt.Errorf("fetching routes: %w", err)
					}

					for _, route := range routes {
						if route.Enabled {
							nodeRoutes[route.NodeID] = append(nodeRoutes[route.NodeID], route.Prefix)
						}
					}

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Free disk space and stop concurrent database users, then restart headscale.
  2. Grant ALTER on the database / UPDATE on nodes to the migration role.
  3. Check pg_stat_activity or lsof on the SQLite file for lock holders.
  4. If it failed mid-transaction, the rollback is automatic - simply retry after fixing the environment.
Defensive patterns

Strategy: try-catch

Try / catch

if _, err := db.NewHeadscaleDatabase(cfg); err != nil {
    if strings.Contains(err.Error(), "adding column types.Node") {
        // ALTER TABLE failed: clear locks, free disk, restart - HasColumn guard makes reruns safe
    }
}

Prevention

When it happens

Trigger: ALTER TABLE nodes ADD COLUMN approved_routes rejected because another session locks nodes, the Postgres role lacks ALTER, or disk is full mid-rewrite.

Common situations: Large nodes table and low disk during SQLite migration; running the server while a long analytics query holds locks; restrictive DB grants in managed Postgres.

Related errors


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