juanfont/headscale · critical
version check: %w
Error message
version check: %w
What it means
Returned by NewHeadscaleDatabase when checkVersionUpgradePath rejects the existing database version before any migration runs. Headscale only supports specific upgrade paths (e.g. pre-v0.25 databases must first be upgraded to v0.25.1, per the comment above the migration list); downgrades and multi-step jumps are refused to protect schema integrity.
Source
Thrown at hscontrol/db/db.go:63
type HSDatabase struct {
DB *gorm.DB
cfg *types.Config
}
// NewHeadscaleDatabase creates a new database connection and runs migrations.
// It accepts the full configuration to allow migrations access to policy settings.
//
//nolint:gocyclo // complex database initialization with many migrations
func NewHeadscaleDatabase(cfg *types.Config) (*HSDatabase, error) {
dbConn, err := openDB(cfg.Database)
if err != nil {
return nil, err
}
err = checkVersionUpgradePath(dbConn)
if err != nil {
return nil, fmt.Errorf("version check: %w", err)
}
migrations := gormigrate.New(
dbConn,
gormigrate.DefaultOptions,
[]*gormigrate.Migration{
// New migrations must be added as transactions at the end of this list.
// Migrations start from v0.25.0. If upgrading from v0.24.x or earlier,
// you must first upgrade to v0.25.1 before upgrading to this version.
// v0.25.0
{
// Add a constraint to routes ensuring they cannot exist without a node.
ID: "202501221827",
Migrate: func(tx *gorm.DB) error {
// Remove any invalid routes associated with a node that does not exist.
if tx.Migrator().HasTable(&types.Route{}) && tx.Migrator().HasTable(&types.Node{}) { //nolint:staticcheck // SA1019: Route kept for migrations
err := tx.Exec("delete from routes where node_id not in (select id from nodes)").ErrorView on GitHub (pinned to 565fd254d0)
Solutions
- Read the wrapped message to see the database's current version vs the supported range.
- To upgrade from pre-v0.25: first run v0.25.1 against the database, then the target version.
- To downgrade: restore a database backup taken before the upgrade - headscale will not migrate backwards.
- Never point two major versions at the same database file.
Defensive patterns
Strategy: try-catch
Try / catch
hsdb, err := db.NewHeadscaleDatabase(cfg)
if err != nil {
if strings.Contains(err.Error(), "version check") {
// database version is unsupported: stop, back up, and upgrade stepwise
log.Fatal().Err(err).Msg("unsupported database version - upgrade via the documented path, do not delete the DB")
}
return err
} Prevention
- Back up the database before every headscale upgrade.
- Upgrade through supported intermediate versions (pre-v0.25 must go via v0.25.1).
- Never run a binary older than the database that wrote it.
- Run the same headscale version for server and CLI against a shared database.
When it happens
Trigger: Starting a new headscale binary against a database written by a much older release (pre-v0.25), or pointing a newer binary at a database created by a NEWER version (downgrade). The wrapped error from versioncheck.go names the offending version.
Common situations: Rolling back a headscale upgrade while keeping the same database; restoring an old database backup onto a new binary; skipping several releases in one upgrade.
Related errors
- headscale version %s cannot be used with a database last use
- headscale version %s cannot be used with a database last use
- headscale version %s cannot be used with a database last use
- automigrating types.Route: %w
- checking if table %s exists: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/0ce4406451d383cd.
Report an issue: GitHub.