juanfont/headscale · error

creating user: %w

Error message

creating user: %w

What it means

Returned by Scenario.CreatePreAuthKey when the headscale control server's gRPC/API call to mint a pre-auth key fails, despite the server handle being available. The message ("creating user") is misleading — the failing operation is headscale.CreateAuthKey for the given user ID.

Source

Thrown at integration/scenario.go:527

	user := &User{
		Clients: make(map[string]TailscaleClient),
	}
	s.users[userStr] = user

	return user
}

// CreatePreAuthKey creates a "pre authentorised key" to be created in the
// Headscale instance on behalf of the [Scenario].
func (s *Scenario) CreatePreAuthKey(
	user uint64,
	reusable bool,
	ephemeral bool,
) (*clientv1.PreAuthKey, error) {
	if headscale, err := s.Headscale(); err == nil { //nolint:noinlineerr
		key, err := headscale.CreateAuthKey(user, reusable, ephemeral)
		if err != nil {
			return nil, fmt.Errorf("creating user: %w", err)
		}

		return key, nil
	}

	return nil, fmt.Errorf("creating user: %w", errNoHeadscaleAvailable)
}

// CreatePreAuthKeyWithOptions creates a "pre authorised key" with the specified options
// to be created in the Headscale instance on behalf of the [Scenario].
func (s *Scenario) CreatePreAuthKeyWithOptions(opts hsic.AuthKeyOptions) (*clientv1.PreAuthKey, error) {
	headscale, err := s.Headscale()
	if err != nil {
		return nil, fmt.Errorf("creating preauth key with options: %w", errNoHeadscaleAvailable)
	}

	key, err := headscale.CreateAuthKeyWithOptions(opts)
	if err != nil {

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Create the user first: s.CreateUser("..."), then use the returned user ID for CreatePreAuthKey
  2. Print the wrapped error — a 'user not found' style message from the gRPC layer confirms the ID problem
  3. Verify the user still exists via headscale.ListUsers if earlier steps may have removed it

Example fix

// before
u, _ := scenario.CreateUser("alice")
key, err := scenario.CreatePreAuthKey(999, false, false)

// after
u, err := scenario.CreateUser("alice")
if err != nil {
    t.Fatal(err)
}
key, err := scenario.CreatePreAuthKey(u.Id, false, false)
Defensive patterns

Strategy: validation

Validate before calling

u, err := scenario.CreateUser(name)
if err != nil {
    t.Fatal(err)
}
// only now is u.Id valid for key creation
_, err = scenario.CreatePreAuthKey(u.Id, reusable, ephemeral)

Try / catch

key, err := scenario.CreatePreAuthKey(u.Id, reusable, ephemeral)
if err != nil {
    t.Fatalf("preauth key creation failed (user %d exists?): %v", u.Id, err)
}

Prevention

When it happens

Trigger: Calling s.CreatePreAuthKey(user, reusable, ephemeral) when the gRPC CreatePreAuthKey call inside the container returns an error, most commonly because the user ID does not exist in headscale.

Common situations: Test passes a user ID before calling s.CreateUser(user), or uses an ID from a different scenario/run; the user was deleted by an earlier test step; API key/machine auth to the local gRPC socket is broken.

Related errors


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