juanfont/headscale · error
setting ACL policy: %w
Error message
setting ACL policy: %w
What it means
Thrown in `headscale policy set --bypass...` when d.SetPolicy() fails writing the validated policy into the database. Because the CLI already ran NewPolicyManager successfully, this is a persistence-layer failure (write/transaction), not a policy-content failure.
Source
Thrown at cmd/headscale/cli/policy.go:154
d, err := openBypassDB(cmd)
if err != nil {
return err
}
defer d.Close()
users, err := d.ListUsers(nil)
if err != nil {
return fmt.Errorf("loading users for policy validation: %w", err)
}
_, err = policy.NewPolicyManager(policyBytes, users, views.Slice[types.NodeView]{})
if err != nil {
return fmt.Errorf("parsing policy file: %w", err)
}
_, err = d.SetPolicy(string(policyBytes))
if err != nil {
return fmt.Errorf("setting ACL policy: %w", err)
}
} else {
policyStr := string(policyBytes)
err := withClient(func(ctx context.Context, client *clientv1.ClientWithResponses) error {
resp, err := client.SetPolicyWithResponse(ctx, clientv1.SetPolicyJSONRequestBody{
Policy: &policyStr,
})
if err != nil {
return fmt.Errorf("setting ACL policy: %w", err)
}
if resp.StatusCode() != http.StatusOK {
return apiError(resp.StatusCode(), resp.ApplicationproblemJSONDefault)
}
return nil
})View on GitHub (pinned to 565fd254d0)
Solutions
- Confirm headscale is stopped and no other process holds the database.
- Check disk space on the database volume.
- Retry the command — the write is a single transaction and idempotent.
- If it persists, inspect SQLite lock state (`fuser <db>`, `lsof <db>`).
Defensive patterns
Strategy: retry
Try / catch
if _, err := d.SetPolicy(string(policyBytes)); err != nil {
if isLocked(err) || isBusy(err) {
// ensure server stopped, then retry once
}
return err
} Prevention
- Single-writer discipline: only one bypass command at a time, server stopped.
- Check disk space before policy writes in constrained environments.
- Back up the database before policy-changing bypass operations.
When it happens
Trigger: SQLite database locked by another process; disk full; transaction aborted; database opened read-only. The policy content has already passed validation at this point.
Common situations: headscale was started again between the confirmation prompt and the write; low disk on the volume holding the SQLite file; container with a read-only mount.
Related errors
- loading policy from database: %w
- loading users for policy validation: %w
- loading users: %w
- loading nodes: %w
- loading config: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/20d44b69b272b10e.
Report an issue: GitHub.