{"record":{"id":"7966a1863712c559","repo":"juanfont/headscale","slug":"listing-users-w-7966a1","errorCode":null,"errorMessage":"listing users: %w","messagePattern":"listing users: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hscontrol/db/db.go","lineNumber":225,"sourceCode":"\t\t\t\t\t// This is a workaround for the fact that the last_seen column\n\t\t\t\t\t// was removed in the 202502171819 migration, but only for some\n\t\t\t\t\t// beta testers.\n\t\t\t\t\tif !tx.Migrator().HasColumn(&types.Node{}, \"last_seen\") {\n\t\t\t\t\t\t_ = tx.Migrator().AddColumn(&types.Node{}, \"last_seen\")\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tRollback: func(db *gorm.DB) error { return nil },\n\t\t\t},\n\t\t\t// Fix the provider identifier for users that have a double slash in the\n\t\t\t// provider identifier.\n\t\t\t{\n\t\t\t\tID: \"202505141324\",\n\t\t\t\tMigrate: func(tx *gorm.DB) error {\n\t\t\t\t\tusers, err := ListUsers(tx, nil)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"listing users: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tfor _, user := range users {\n\t\t\t\t\t\tuser.ProviderIdentifier.String = types.CleanIdentifier(user.ProviderIdentifier.String)\n\n\t\t\t\t\t\terr := tx.Save(user).Error\n\t\t\t\t\t\tif err != nil {\n\t\t\t\t\t\t\treturn fmt.Errorf(\"saving user: %w\", err)\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn nil\n\t\t\t\t},\n\t\t\t\tRollback: func(db *gorm.DB) error { return nil },\n\t\t\t},\n\t\t\t// v0.27.0\n\t\t\t// Schema migration to ensure all tables match the expected schema.\n\t\t\t// This migration recreates all tables to match the exact structure in schema.sql,","sourceCodeStart":207,"sourceCodeEnd":243,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/db/db.go#L207-L243","documentation":"Migration 202505141324 (fixing double slashes in user provider identifiers) failed at ListUsers(tx, nil). The SELECT could not complete: connection failure, lock timeout, or a schema where the users table lacks expected columns for scanning into types.User.","triggerScenarios":"Listing all users during upgrade while another session locks users; Postgres connection dropped; users table drifted from types.User so GORM's generated SELECT references missing columns.","commonSituations":"OIDC-enabled deployments with many users hitting a slow query timeout; upgrading a database previously run with an incompatible fork.","solutions":["Check the wrapped error for missing column names - that indicates schema drift needing manual repair.","For lock/timeout errors, stop concurrent access and retry the upgrade.","Back up the database before upgrade so you can retry safely.","Confirm headscale binary version matches the database generation path (see version check)."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if _, err := db.NewHeadscaleDatabase(cfg); err != nil {\n    if strings.Contains(err.Error(), \"listing users\") {\n        // check for missing columns (schema drift) or lock/timeout in the wrapped error\n    }\n}","preventionTips":["Back up before upgrades that touch user data (202505141324).","Keep user counts and OIDC data maintained; delete defunct test users.","Do not modify the users table out-of-band."],"tags":["database","migration","user","oidc","gorm"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}