{"record":{"id":"42d46c175a41a027","repo":"juanfont/headscale","slug":"loading-acl-policy-w","errorCode":null,"errorMessage":"loading ACL policy: %w","messagePattern":"loading ACL policy: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"cmd/headscale/cli/policy.go","lineNumber":96,"sourceCode":"\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\tpol, err := d.GetPolicy()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"loading policy from database: %w\", err)\n\t\t\t}\n\n\t\t\tpolicyData = pol.Data\n\t\t} else {\n\t\t\terr := withClient(func(ctx context.Context, client *clientv1.ClientWithResponses) error {\n\t\t\t\tresp, err := client.GetPolicyWithResponse(ctx)\n\t\t\t\tif err != nil {\n\t\t\t\t\treturn fmt.Errorf(\"loading ACL policy: %w\", err)\n\t\t\t\t}\n\n\t\t\t\tif resp.StatusCode() != http.StatusOK {\n\t\t\t\t\treturn apiError(resp.StatusCode(), resp.ApplicationproblemJSONDefault)\n\t\t\t\t}\n\n\t\t\t\tpolicyData = resp.JSON200.Policy\n\n\t\t\t\treturn nil\n\t\t\t})\n\t\t\tif err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\t\t}\n\n\t\t// This does not pass output format as we don't support yaml, json or\n\t\t// json-line output for this command. It is HuJSON already.\n\t\tfmt.Println(policyData)","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/cmd/headscale/cli/policy.go#L78-L114","documentation":"Thrown in `headscale policy get` (server mode) when client.GetPolicyWithResponse() fails at the transport level — the HTTP request to the headscale API never completed. This is distinct from the apiError branch which handles non-200 responses.","triggerScenarios":"headscale server not running or unreachable at the configured address; wrong port; TLS certificate mismatch; DNS failure; connection refused/reset. Note: an HTTP 4xx/5xx does NOT produce this error — that goes through apiError.","commonSituations":"CLI run on a machine without access to the server; server_url pointing at stale address after moving the deployment; self-signed cert without the CLI trusting it; firewall dropping the connection.","solutions":["Check the server is up: `curl -v <server_url>/api/v1/policy`.","Verify the configured server address and API key in the CLI environment.","If TLS is the issue, ensure the certificate is trusted by the CLI host or fix server_url to match the cert.","If the server is intentionally down, use the --bypass-server-and-access-database-directly flag instead."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// pre-flight: server API reachable?\nfunc pingAPI(serverURL string, apiKey string) error {\n    req, _ := http.NewRequest(\"GET\", serverURL+\"/api/v1/apikey\", nil)\n    req.Header.Set(\"Authorization\", \"Bearer \"+apiKey)\n    resp, err := http.DefaultClient.Do(req)\n    if err != nil {\n        return err\n    }\n    resp.Body.Close()\n    if resp.StatusCode >= 500 {\n        return fmt.Errorf(\"server unhealthy: %d\", resp.StatusCode)\n    }\n    return nil\n}","typeGuard":"func isTransportError(err error) bool {\n    return err != nil && !strings.Contains(err.Error(), \"api error (\")\n}","tryCatchPattern":"err := withClient(func(ctx, c) error { ... GetPolicyWithResponse ... })\nif err != nil && isTransportError(err) {\n    // network-level: backoff and retry once; if still failing, fall back to --bypass only if server is confirmed down\n}","preventionTips":["Health-check the server before scripted policy operations.","Prefer server mode for reads; reserve bypass for maintenance windows.","Pin server_url in one place (env/config) so all CLI hosts agree."],"tags":["network","http","cli","policy"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}