{"record":{"id":"f28091ee5c2595c4","repo":"juanfont/headscale","slug":"headscale-version-s-cannot-be-used-with-a-databas","errorCode":null,"errorMessage":"headscale version %s cannot be used with a database last used by %s: %w","messagePattern":"headscale version (.+?) cannot be used with a database last used by (.+?): %w","errorType":"console","errorClass":"errVersionMajorChange","httpStatus":null,"severity":"critical","filePath":"hscontrol/db/versioncheck.go","lineNumber":239,"sourceCode":"\t}\n\n\t// Previous run was an unversioned build — no meaningful comparison.\n\tif isDev(storedVersion) {\n\t\treturn nil\n\t}\n\n\tcurrent, err := parseVersion(currentVersion)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing current version: %w\", err)\n\t}\n\n\tstored, err := parseVersion(storedVersion)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parsing stored database version: %w\", err)\n\t}\n\n\tif current.Major != stored.Major {\n\t\treturn fmt.Errorf(\n\t\t\t\"headscale version %s cannot be used with a database last used by %s: %w\",\n\t\t\tcurrentVersion, storedVersion, errVersionMajorChange,\n\t\t)\n\t}\n\n\tminorDiff := current.Minor - stored.Minor\n\n\tswitch {\n\tcase minorDiff == 0:\n\t\t// Same minor version — patch changes are always fine.\n\t\treturn nil\n\n\tcase minorDiff == 1:\n\t\t// Single minor version upgrade — allowed.\n\t\treturn nil\n\n\tcase minorDiff > 1:\n\t\t// Multi-minor upgrade — blocked.","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/db/versioncheck.go#L221-L257","documentation":"The version compatibility check found that the database was last written by a headscale release with a different MAJOR version than the running binary. Major versions imply breaking schema changes, so headscale refuses to touch the database. The sentinel errVersionMajorChange is wrapped for programmatic detection.","triggerScenarios":"Starting a headscale vN binary against a database whose stored version has major != N — e.g. after a major release upgrade or downgrade, or pointing dns/db config at a database file from another headscale major version.","commonSituations":"Upgrading headscale across a major version boundary in one step; restoring a backup made by a different major version; two installations sharing one database file.","solutions":["Check the stored version (shown in the message) and the running binary version (headscale version).","Follow the release notes for the major upgrade path — typically export/migrate data or start from the intermediate major version.","If the database is disposable (test/dev), delete or move the SQLite file (or drop the Postgres database) and let headscale recreate it.","Never hand-edit the stored version row to force compatibility."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before starting, compare versions if you can read the stored version:\n// (simplified; headscale does this internally at startup)\nif current.Major != stored.Major {\n    return fmt.Errorf(\"refusing to run: database is from major version %d, binary is %d\", stored.Major, current.Major)\n}","typeGuard":null,"tryCatchPattern":"if err := db.CheckVersion(...); err != nil {\n    if errors.Is(err, errVersionMajorChange) {\n        // hard stop: export/migrate via the documented major-upgrade path or start fresh\n        log.Fatal().Err(err).Msg(\"incompatible database major version\")\n    }\n}","preventionTips":["Back up the database before any headscale upgrade.","Pin versions in deployment tooling and read release notes before major bumps.","Never share one database between installations of different major versions."],"tags":["versioning","database","migration","startup"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}