{"record":{"id":"450dab6729a3b7ff","repo":"juanfont/headscale","slug":"loading-users-for-policy-validation-w","errorCode":null,"errorMessage":"loading users for policy validation: %w","messagePattern":"loading users for policy validation: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/headscale/cli/policy.go","lineNumber":144,"sourceCode":"\tAliases: []string{\"put\", \"update\"},\n\tRunE: func(cmd *cobra.Command, args []string) error {\n\t\tpolicyPath, _ := cmd.Flags().GetString(\"file\")\n\n\t\tpolicyBytes, err := os.ReadFile(policyPath)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"reading policy file: %w\", err)\n\t\t}\n\n\t\tif bypass, _ := cmd.Flags().GetBool(bypassFlag); bypass {\n\t\t\td, err := openBypassDB(cmd)\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t\tdefer d.Close()\n\n\t\t\tusers, err := d.ListUsers(nil)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"loading users for policy validation: %w\", err)\n\t\t\t}\n\n\t\t\t_, err = policy.NewPolicyManager(policyBytes, users, views.Slice[types.NodeView]{})\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"parsing policy file: %w\", err)\n\t\t\t}\n\n\t\t\t_, err = d.SetPolicy(string(policyBytes))\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"setting ACL policy: %w\", err)\n\t\t\t}\n\t\t} else {\n\t\t\tpolicyStr := string(policyBytes)\n\n\t\t\terr := withClient(func(ctx context.Context, client *clientv1.ClientWithResponses) error {\n\t\t\t\tresp, err := client.SetPolicyWithResponse(ctx, clientv1.SetPolicyJSONRequestBody{\n\t\t\t\t\tPolicy: &policyStr,\n\t\t\t\t})","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/headscale/cli/policy.go#L126-L162","documentation":"Thrown in `headscale policy set --bypass...` when d.ListUsers(nil) fails after opening the database directly. Users are loaded so policy.NewPolicyManager can validate that every user referenced in the HuJSON exists. Failure is at the database read layer, before policy parsing.","triggerScenarios":"Bypass-mode set where the users table query fails: corrupt database, concurrent writer holding a lock (headscale still running), or schema mismatch after a partial migration.","commonSituations":"Forgetting to stop headscale before bypass operations; database file copied/restored mid-migration; running bypass against a file with wrong ownership.","solutions":["Stop the headscale service before bypass commands.","Verify with the non-bypass path (`headscale users list`) once the server is up — if that also fails, the database itself needs attention.","Check SQLite integrity: `sqlite3 <db> 'PRAGMA integrity_check;'`.","Restore from backup if corruption is confirmed."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"users, err := d.ListUsers(nil)\nif err != nil {\n    if isLocked(err) { // 'database is locked' in wrapped text\n        // stop headscale, retry once\n    }\n    return err\n}","preventionTips":["Always stop headscale before bypass commands — encode as a wrapper script.","Alert on 'database is locked' in logs; it indicates concurrent access.","Snapshot the database before bypass writes."],"tags":["database","policy","cli","bypass"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}