juanfont/headscale · critical
running migration 202501311657: %w
Error message
running migration 202501311657: %w
What it means
On sqlite, headscale first migrates up to and including migration '202501311657' with foreign keys disabled — the last migration permitted to run FK-off (the set is frozen as of 2025-07-02). This error means one of those early migrations failed during MigrateTo.
Source
Thrown at hscontrol/db/db.go:1175
)
}
func runMigrations(cfg types.DatabaseConfig, dbConn *gorm.DB, migrations *gormigrate.Gormigrate) error {
if cfg.Type == types.DatabaseSqlite {
// SQLite: Run the early migrations that GORM cannot handle safely with
// foreign keys enabled (route and pre-auth-key automigrations) with FK
// disabled, then run everything else with FK enabled.
//
// NO NEW MIGRATIONS SHOULD RUN WITH FK DISABLED. As of 2025-07-02, all
// new migrations must run with foreign keys enabled via the
// migrations.Migrate() call below.
if err := dbConn.Exec("PRAGMA foreign_keys = OFF").Error; err != nil { //nolint:noinlineerr
return fmt.Errorf("disabling foreign keys: %w", err)
}
// Run up to and including the last migration that requires FK disabled.
if err := migrations.MigrateTo("202501311657"); err != nil { //nolint:noinlineerr
return fmt.Errorf("running migration 202501311657: %w", err)
}
if err := dbConn.Exec("PRAGMA foreign_keys = ON").Error; err != nil { //nolint:noinlineerr
return fmt.Errorf("restoring foreign keys: %w", err)
}
// Run the rest of the migrations
if err := migrations.Migrate(); err != nil { //nolint:noinlineerr
return err
}
// Check for constraint violations at the end
type constraintViolation struct {
Table string
RowID int
Parent string
ConstraintIndex int
}View on GitHub (pinned to 565fd254d0)
Solutions
- Read the chained gormigrate error to identify the failing early migration.
- Validate the sqlite file: sqlite3 headscale.db 'PRAGMA integrity_check;'.
- Restore from a known-good backup or litestream replica if integrity fails.
- For a fresh start, move the DB file aside and let headscale recreate it, then re-register nodes.
Defensive patterns
Strategy: fallback
Validate before calling
// Pre-migration integrity check for sqlite: // sqlite3 headscale.db 'PRAGMA integrity_check;' # expect: ok // sqlite3 headscale.db 'SELECT * FROM schema_migrations;' # inspect version state
Try / catch
// On failure, fall back to the most recent backup/replica: // restore, verify integrity, restart headscale. Do not hand-edit // schema_migrations to 'skip' a migration.
Prevention
- Maintain continuous backups (litestream for sqlite, pg_dump schedules for postgres).
- Test upgrades on a copy of production data first.
- Avoid interrupting headscale during startup/migration windows.
When it happens
Trigger: An existing database whose early schema disagrees with the migration scripts (schema_migrations records a version but the tables were altered), or a lock/corruption issue during the early phase. Also fires on fresh DBs if InitSchema's AutoMigrate step fails.
Common situations: Database restored from a partial backup; schema edited by external tooling; sqlite file truncated. Distinct from later-migration failures (error 400/401 path) because these run with FKs off.
Related errors
- foreign key constraints violated
- automigrating types.Route: %w
- automigrating types.Node: %w
- setting auth_key to null on nodes with non-existing keys: %w
- adding column types.Node: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/c8243a7915d9fa8c.
Report an issue: GitHub.