juanfont/headscale · critical
automigrating types.Node: %w
Error message
automigrating types.Node: %w
What it means
Migration 202501311657 failed at tx.AutoMigrate(&types.Node{}) - the second step that re-aligns the nodes table with the current Go struct (part of the same migration that restores the pre-auth-key FK). Failure means DDL on the nodes table was rejected: locks, permissions, or an incompatible existing column type.
Source
Thrown at hscontrol/db/db.go:116
}
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
SET auth_key_id = NULL
WHERE auth_key_id IS NOT NULL
AND auth_key_id NOT IN (
SELECT id FROM pre_auth_keys
);View on GitHub (pinned to 565fd254d0)
Solutions
- Free disk space at least equal to the nodes table size (SQLite needs room for the rewrite).
- Terminate blocking sessions / stop the old headscale process before restarting.
- Inspect the wrapped error for the specific column/DDL that failed and compare against types.Node.
- Restore the pre-migration backup if the migration aborted mid-transaction.
Defensive patterns
Strategy: try-catch
Try / catch
if _, err := db.NewHeadscaleDatabase(cfg); err != nil {
if strings.Contains(err.Error(), "automigrating types.Node") {
// DDL on nodes failed: free disk (SQLite table rewrite), clear locks, restart
}
} Prevention
- Reserve free disk at least the size of the nodes table before upgrading.
- Terminate long-running queries against nodes before restarting headscale.
- Avoid schema modifications from forks - they make AutoMigrate fail on upgrade.
When it happens
Trigger: AutoMigrate attempts to alter nodes while another connection holds a lock; a nodes column type changed between versions in a way SQLite cannot remap; disk full during table rewrite (SQLite alters copy the table).
Common situations: Large nodes table with insufficient disk for SQLite's copy-on-alter; Postgres ACCESS EXCLUSIVE lock blocked by a long-running query; upgrading a database that a forked build modified.
Related errors
- automigrating types.Route: %w
- adding prefix column: %w
- foreign key constraints violated
- saving API key to database: %w
- automigrating types.PreAuthKey: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/0b87ef83c1e76759.
Report an issue: GitHub.