{"record":{"id":"c4b41dbed76590c4","repo":"juanfont/headscale","slug":"parsing-policy-file-w","errorCode":null,"errorMessage":"parsing policy file: %w","messagePattern":"parsing policy file: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/headscale/cli/policy.go","lineNumber":149,"sourceCode":"\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})\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"setting ACL policy: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif resp.StatusCode() != http.StatusOK {","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/headscale/cli/policy.go#L131-L167","documentation":"Thrown in `headscale policy set --bypass...` when policy.NewPolicyManager(policyBytes, users, nodes) rejects the policy HuJSON. In bypass mode the CLI pre-validates structure and user references (the boot path, which deliberately skips test evaluation) before writing, so this fires on malformed HuJSON or references to nonexistent users.","triggerScenarios":"Syntax errors in the HuJSON (missing comma, unbalanced braces); a \"user\" field naming a user that does not exist in the database; unknown autogroup/tag syntax; invalid CIDR in address rules; tag referenced without an owner.","commonSituations":"Editing policy by hand and referencing a deleted or renamed user; merging policies from another tailnet; trailing commas accepted in some HuJSON tooling but not others; policy written against a newer headscale syntax than the installed version.","solutions":["Read the wrapped error — the v2 policy parser reports the exact path and position of the offending element.","Cross-check every user/email in the policy against `headscale users list`.","Run `headscale policy check --file <path>` against the live server to iterate faster before re-trying set.","Validate HuJSON syntax with a HuJSON-aware formatter."],"exampleFix":"// before: references a user that was deleted\n{\"grants\":[{\"src\":[\"old-user@\"],\"dst\":[\"tag:server\"],\"ip\":[\"*\"]}]}\n\n// after\n{\"grants\":[{\"src\":[\"current-user@\"],\"dst\":[\"tag:server\"],\"ip\":[\"*\"]}]}","handlingStrategy":"validation","validationCode":"// cheap pre-parse before the CLI's full validation\nfunc hujsonParses(b []byte) error {\n    var v any\n    return json.Unmarshal(b, &v) // HuJSON with comments will fail; strip comments first or use hujson tooling\n}","typeGuard":null,"tryCatchPattern":"_, err := policy.NewPolicyManager(policyBytes, users, views.Slice[types.NodeView]{})\nif err != nil {\n    // parser error names path+position: fix file, re-run; do NOT fall back to writing unvalidated bytes to the DB\n    return err\n}","preventionTips":["Run `headscale policy check --file X` (server mode) as a CI gate on every policy change.","Generate policy with a HuJSON formatter to catch syntax errors locally.","Keep user references generated from `headscale users list` output rather than typed by hand."],"tags":["policy","validation","cli","hujson"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}