juanfont/headscale · error
loading database policy on startup: %w
Error message
loading database policy on startup: %w
What it means
Thrown when pool.Retry(hsic.reloadDatabasePolicy) exhausts its retries. In PolicyModeDB with an aclPolicy set, the policy must be loaded into the database via the container CLI before headscale starts (the container sleeps, then boots). reloadDatabasePolicy runs the load command repeatedly; persistent failure means headscale cannot ingest the policy file.
Source
Thrown at integration/hsic/hsic.go:636
err = hsic.WriteFile(tlsKeyPath, hsic.tlsKey)
if err != nil {
return nil, fmt.Errorf("writing TLS key to container: %w", err)
}
}
for _, f := range hsic.filesInContainer {
err := hsic.WriteFile(f.path, f.contents)
if err != nil {
return nil, fmt.Errorf("writing %q: %w", f.path, err)
}
}
// Load the database from policy file on repeat until it succeeds,
// this is done as the container sleeps before starting headscale.
if hsic.aclPolicy != nil && hsic.policyMode == types.PolicyModeDB {
err := pool.Retry(hsic.reloadDatabasePolicy)
if err != nil {
return nil, fmt.Errorf("loading database policy on startup: %w", err)
}
}
return hsic, nil
}
func (t *HeadscaleInContainer) ConnectToNetwork(network *dockertest.Network) error {
return t.container.ConnectToNetwork(network)
}
func (t *HeadscaleInContainer) hasTLS() bool {
return len(t.tlsCert) != 0 && len(t.tlsKey) != 0
}
// Shutdown stops and cleans up the Headscale container.
func (t *HeadscaleInContainer) Shutdown() (string, string, error) {
stdoutPath, stderrPath, err := t.SaveLog("/tmp/control")
if err != nil {View on GitHub (pinned to 565fd254d0)
Solutions
- Run the load command manually: docker exec <hs> headscale policy load /etc/headscale/acl.hujson ... to see the exact policy error
- Validate the policy HuJSON locally against hscontrol/policy/v2 semantics
- Check that any tags/users referenced by the policy exist or are declared in the policy itself
- If the mode was unintended, use file policy mode instead of PolicyModeDB
Defensive patterns
Strategy: validation
Validate before calling
// Validate policy once before container setup
tmp := t.TempDir() + "/acl.hujson"
os.WriteFile(tmp, serializedPolicy, 0o600)
if out, err := exec.Command(headscaleBin, "policy", "load", "--test", tmp).CombinedOutput(); err != nil {
t.Fatalf("policy rejected: %v\n%s", err, out)
} Try / catch
if err := pool.Retry(hsic.reloadDatabasePolicy); err != nil {
// re-run the load command manually to capture the exact CLI error for the report
t.Fatalf("policy load failed; policy likely invalid: %v", err)
} Prevention
- Lint HuJSON policies with headscale policy check/load --test before integration runs
- Ensure referenced tags/users exist or are defined within the policy
- Track policy-syntax changes when bumping headscale versions
When it happens
Trigger: HeadscaleInContainer built with WithACLPolicy and database policy mode: `headscale policy load` (or equivalent) inside the container keeps failing — invalid HuJSON/ACL syntax, unknown autogroup/tag references, or the headscale binary erroring on the policy — until pool.Retry gives up.
Common situations: Policy file with syntax errors or referencing undefined tags/users; policy written to the container (error 675 succeeded) but semantically invalid; version change in policy semantics between headscale releases.
Related errors
- unknown field
- loading policy from database: %w
- loading users for policy validation: %w
- parsing policy file: %w
- setting ACL policy: %w
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/5b490558041f9b77.
Report an issue: GitHub.