juanfont/headscale · error

user %s not found

Error message

user %s not found

What it means

Returned by the integration helper GetUserByName when ListUsers succeeded but no user with the requested name exists. It is a plain fmt.Errorf (marked nolint:err113) with the missing username.

Source

Thrown at integration/helpers.go:1086

		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
		}
	}

	return nil
}

// mustParseID parses a string ID emitted by the HTTP client types into a
// uint64 for the APIs that still take numeric identifiers (NodeID, user and
// key IDs). It panics on malformed input, which only happens if the server
// emits a non-numeric ID — a bug worth failing the test loudly.

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Create the user (scenario.CreateUser / preauth flow) before calling GetUserByName
  2. Verify the exact name string, including case, matches the one used at creation
  3. Assert on list contents directly if absence is expected, instead of treating it as an error
Defensive patterns

Strategy: validation

Validate before calling

// create-if-missing pattern
users, _ := h.ListUsers()
exists := slices.ContainsFunc(users, func(u *clientv1.User) bool { return u.Name == username })
if !exists {
    if _, err := scenario.CreateUser(username); err != nil {
        return err
    }
}

Try / catch

u, err := GetUserByName(h, username)
if err != nil {
    if strings.Contains(err.Error(), "not found") {
        // create the user, then retry the lookup once
    }
    return err
}

Prevention

When it happens

Trigger: Calling GetUserByName(t, headscale, "nonexistent") before that user was created, or after a cleanup removed it; also when the name has different case/whitespace than what was registered.

Common situations: Test ordering bugs — helper runs before the user-creation step; typos or case mismatches between the scenario users list and the lookup; parallel tests deleting shared users.

Related errors


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