{"record":{"id":"b81c20538e900157","repo":"juanfont/headscale","slug":"loading-users-w","errorCode":null,"errorMessage":"loading users: %w","messagePattern":"loading users: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/headscale/cli/policy.go","lineNumber":209,"sourceCode":"\topen the database directly when headscale is not running.`,\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: %w\", err)\n\t\t\t}\n\n\t\t\tnodes, err := d.ListNodes()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"loading nodes: %w\", err)\n\t\t\t}\n\n\t\t\t// [policy.NewPolicyManager] validates structure and user references\n\t\t\t// but intentionally skips test evaluation (boot path).\n\t\t\t// [policy.PolicyManager.SetPolicy] is the user-write boundary and is what runs the\n\t\t\t// tests and sshTests blocks.\n\t\t\tpm, err := policy.NewPolicyManager(policyBytes, users, nodes.ViewSlice())\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 = pm.SetPolicy(policyBytes)\n\t\t\tif err != nil {","sourceCodeStart":191,"sourceCodeEnd":227,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/headscale/cli/policy.go#L191-L227","documentation":"Thrown in `headscale policy check --bypass...` when d.ListUsers(nil) fails on the directly-opened database. Users (and then nodes) are loaded to construct a PolicyManager that validates the policy against the tailnet's real identities.","triggerScenarios":"Bypass-mode check with headscale still running (SQLite lock), corrupt database, or schema mismatch — the users query itself errors before policy validation begins.","commonSituations":"Using check --bypass as a lint step while the server is live; copied database file with broken journal; permissions changed after a system update.","solutions":["Stop headscale before running bypass commands.","Test the same read through the server path (`headscale users list`) to isolate database vs. API issues.","Run `PRAGMA integrity_check` on the SQLite file.","If locked, find the holder: `lsof <db-file>`."],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":"users, err := d.ListUsers(nil)\nif err != nil {\n    if isLocked(err) {\n        // stop headscale, retry check once\n    }\n    return err\n}","preventionTips":["Prefer server-mode `policy check` when headscale is up; bypass only when down.","Script the stop -> check -> start sequence for maintenance windows.","Monitor for concurrent-access errors in database logs."],"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"}