juanfont/headscale · error

loading users: %w

Error message

loading users: %w

What it means

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.

Source

Thrown at cmd/headscale/cli/policy.go:209

	open the database directly when headscale is not running.`,
	RunE: func(cmd *cobra.Command, args []string) error {
		policyPath, _ := cmd.Flags().GetString("file")

		policyBytes, err := os.ReadFile(policyPath)
		if err != nil {
			return fmt.Errorf("reading policy file: %w", err)
		}

		if bypass, _ := cmd.Flags().GetBool(bypassFlag); bypass {
			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: %w", err)
			}

			nodes, err := d.ListNodes()
			if err != nil {
				return fmt.Errorf("loading nodes: %w", err)
			}

			// [policy.NewPolicyManager] validates structure and user references
			// but intentionally skips test evaluation (boot path).
			// [policy.PolicyManager.SetPolicy] is the user-write boundary and is what runs the
			// tests and sshTests blocks.
			pm, err := policy.NewPolicyManager(policyBytes, users, nodes.ViewSlice())
			if err != nil {
				return fmt.Errorf("parsing policy file: %w", err)
			}

			_, err = pm.SetPolicy(policyBytes)
			if err != nil {

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Stop headscale before running bypass commands.
  2. Test the same read through the server path (`headscale users list`) to isolate database vs. API issues.
  3. Run `PRAGMA integrity_check` on the SQLite file.
  4. If locked, find the holder: `lsof <db-file>`.
Defensive patterns

Strategy: validation

Try / catch

users, err := d.ListUsers(nil)
if err != nil {
    if isLocked(err) {
        // stop headscale, retry check once
    }
    return err
}

Prevention

When it happens

Trigger: Bypass-mode check with headscale still running (SQLite lock), corrupt database, or schema mismatch — the users query itself errors before policy validation begins.

Common situations: Using check --bypass as a lint step while the server is live; copied database file with broken journal; permissions changed after a system update.

Related errors


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/b81c20538e900157. Report an issue: GitHub.