{"record":{"id":"55891a803b5f4802","repo":"juanfont/headscale","slug":"loading-nodes-for-requesttags-migration-w","errorCode":null,"errorMessage":"loading nodes for RequestTags migration: %w","messagePattern":"loading nodes for RequestTags migration: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"hscontrol/db/db.go","lineNumber":627,"sourceCode":"\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Warn().Err(err).Msg(\"failed to load policy, skipping RequestTags migration (tags will be validated on node reconnect)\")\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\tif len(policyData) == 0 {\n\t\t\t\t\t\tlog.Info().Msg(\"no policy found, skipping RequestTags migration (tags will be validated on node reconnect)\")\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\t// 2. Load users and nodes to create PolicyManager\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(\"loading users for RequestTags migration: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\tnodes, err := ListNodes(tx)\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\treturn fmt.Errorf(\"loading nodes for RequestTags migration: %w\", err)\n\t\t\t\t\t}\n\n\t\t\t\t\t// 3. Create PolicyManager (handles HuJSON parsing, groups, nested tags, etc.)\n\t\t\t\t\tpolMan, err := policy.NewPolicyManager(policyData, users, nodes.ViewSlice())\n\t\t\t\t\tif err != nil {\n\t\t\t\t\t\tlog.Warn().Err(err).Msg(\"failed to parse policy, skipping RequestTags migration (tags will be validated on node reconnect)\")\n\t\t\t\t\t\treturn nil\n\t\t\t\t\t}\n\n\t\t\t\t\t// 4. Process each node\n\t\t\t\t\tfor _, node := range nodes {\n\t\t\t\t\t\tif node.Hostinfo == nil {\n\t\t\t\t\t\t\tcontinue\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\trequestTags := node.Hostinfo.RequestTags\n\t\t\t\t\t\tif len(requestTags) == 0 {\n\t\t\t\t\t\t\tcontinue","sourceCodeStart":609,"sourceCodeEnd":645,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/db/db.go#L609-L645","documentation":"The same RequestTags migration fails at ListNodes(tx): it must load every node (with Hostinfo JSON) to decide which nodes' historical RequestTags can be merged into the new tags column. Failure is a SELECT-level error on nodes - schema mismatch (e.g. tags column missing because the preceding rename migration mis-applied), permissions, locks, or resource exhaustion during the full-table load.","triggerScenarios":"nodes table schema drift (e.g. tags column missing because migration 202511131445's earlier rename step failed), lock timeout on nodes, connection loss, or extremely large node counts exhausting container memory during the full-table scan.","commonSituations":"Big tailnets upgrading on memory-limited containers; databases restored with mismatched schema; concurrent writers during the migration window.","solutions":["Read the wrapped error: 'no such column: tags' means the earlier rename step failed - reconcile schema/history before retrying","Upgrade during a quiet window with no peer/admin writes to nodes","Raise the container's memory limit for the upgrade of very large tailnets, or prune dead nodes first (headscale nodes delete) to shrink the scan","Retry startup after fixing connectivity; the migration transaction is atomic and replays safely"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Pre-flight for large tailnets: estimate migration memory cost\nvar nodeCount int\ndb.QueryRow(\"SELECT count(*) FROM nodes\").Scan(&nodeCount)\nif nodeCount > 50000 {\n\tlog.Printf(\"large node count (%d); ensure ample memory for the RequestTags migration\", nodeCount)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prune expired/dead nodes before major upgrades","Size container memory for the full-table load this migration performs","Quiesce peer traffic during the upgrade window"],"tags":["database","migration","nodes","policy","memory"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}