juanfont/headscale · error
listing users: %w
Error message
listing users: %w
What it means
Returned by the integration helper GetUserByName when headscale.ListUsers (the gRPC/API call to the control server) fails. It wraps the transport/API error; the user-lookup itself hasn't started yet.
Source
Thrown at integration/helpers.go:1077
// oidcMockUser creates a [mockoidc.MockUser] for OIDC authentication testing.
// Generates consistent test user data with configurable email verification status
// for validating OIDC integration flows in headscale authentication tests.
func oidcMockUser(username string, emailVerified bool) mockoidc.MockUser {
return mockoidc.MockUser{
Subject: username,
PreferredUsername: username,
Email: username + "@headscale.net",
EmailVerified: emailVerified,
}
}
// GetUserByName retrieves a user by name from the headscale server.
// This is a common pattern used when creating preauth keys or managing users.
func GetUserByName(headscale ControlServer, username string) (*clientv1.User, error) {
users, err := headscale.ListUsers()
if err != nil {
return nil, fmt.Errorf("listing users: %w", err)
}
for _, u := range users {
if u.Name == username {
return u, nil
}
}
return nil, fmt.Errorf("user %s not found", username) //nolint:err113
}
// findNode returns the first node in nodes for which match returns true,
// or nil if no node matches.
func findNode(nodes []*clientv1.Node, match func(*clientv1.Node) bool) *clientv1.Node {
for _, n := range nodes {
if match(n) {
return n
}View on GitHub (pinned to 565fd254d0)
Solutions
- Check the headscale container is healthy before the failing step (control_logs / hi doctor)
- Inspect the wrapped error for gRPC status codes (Unavailable, Unauthenticated) and fix transport/auth accordingly
- Re-create the control-server client after server restarts instead of reusing a dead connection
Defensive patterns
Strategy: try-catch
Validate before calling
// health gate before lookups
func controlHealthy(h ControlServer) error {
if _, err := h.ListUsers(); err != nil {
return fmt.Errorf("control plane not ready: %w", err)
}
return nil
} Try / catch
u, err := GetUserByName(h, name)
if err != nil {
if strings.Contains(err.Error(), "listing users") {
// transport/API problem: recreate client, check container, then retry once
}
// 'not found' branch: create the user first
return err
} Prevention
- Create users before tests that look them up
- Rebuild control clients after server restarts; don't reuse pooled gRPC connections
When it happens
Trigger: Calling GetUserByName in a test when the control-server client is misconfigured, the headscale container is down/restarting, or the API returns an error (auth, unavailable).
Common situations: Test harness points at a stale server URL; headscale container crashed earlier in the test; API key expired mid-run; grpc connection pool reused after server restart.
Related errors
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/2c976011823bc277.
Report an issue: GitHub.