kubernetes/kops · error

failed to create pool association: %v

Error message

failed to create pool association: %v

What it means

Wrapped failure from v2pools.CreateMember in associateToPool's writeBackoff loop. Association lookup succeeded (member absent), but creating the new pool member failed at the Octavia API; the underlying gophercloud error is embedded via %v.

Source

Thrown at upup/pkg/fi/cloudup/openstack/loadbalancer.go:415

	return association, nil
}

func (c *openstackCloud) AssociateToPool(server *servers.Server, poolID string, opts v2pools.CreateMemberOpts) (association *v2pools.Member, err error) {
	return associateToPool(c, server, poolID, opts)
}

func associateToPool(c OpenstackCloud, server *servers.Server, poolID string, opts v2pools.CreateMemberOpts) (association *v2pools.Member, err error) {
	if c.LoadBalancerClient() == nil {
		return nil, fmt.Errorf("loadbalancer support not available in this deployment")
	}

	done, err := vfs.RetryWithBackoff(writeBackoff, func() (bool, error) {
		association, err = v2pools.GetMember(context.TODO(), c.LoadBalancerClient(), poolID, server.ID).Extract()
		if err != nil || association == nil {
			// Pool association does not exist.  Create it
			association, err = v2pools.CreateMember(context.TODO(), c.LoadBalancerClient(), poolID, opts).Extract()
			if err != nil {
				return false, fmt.Errorf("failed to create pool association: %v", err)
			}
			return true, nil
		}
		// NOOP
		return true, nil
	})
	if !done {
		if err == nil {
			err = wait.ErrWaitTimeout
		}
		return association, err
	}
	return association, nil
}

func (c *openstackCloud) CreatePool(opts v2pools.CreateOpts) (pool *v2pools.Pool, err error) {
	return createPool(c, opts)
}

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Read the wrapped %v error: 404/409 indicate the pool is gone or immutable — verify pool existence and wait for PENDING states to clear.
  2. Validate CreateMemberOpts: address must belong to the pool's subnet-id configured in the kOps cluster spec.
  3. Check Octavia member quotas (`openstack quota show`) and raise if exceeded.
  4. Verify keystone permissions to create members in the target project.

Example fix

// before
opts := v2pools.CreateMemberOpts{Address: nodeIP, ProtocolPort: 443} // missing SubnetID
// after
opts := v2pools.CreateMemberOpts{Address: nodeIP, ProtocolPort: 443, SubnetID: poolSubnetID}
Defensive patterns

Strategy: try-catch

Validate before calling

member, _ := cloud.GetPoolMember(poolID, server.ID)
if member == nil && (opts.SubnetID == "" || opts.Address == "") {
	return fmt.Errorf("invalid CreateMemberOpts: address and subnet-id required")
}

Try / catch

assoc, err := cloud.AssociateToPool(server, poolID, opts)
if err != nil {
	if strings.Contains(err.Error(), "failed to create pool association") {
		if strings.Contains(err.Error(), "409") {
			return retryLater(err) // pool immutable
		}
		if strings.Contains(err.Error(), "404") {
			return ErrPoolGone
		}
	}
	return err
}

Prevention

When it happens

Trigger: CreateMember rejected due to invalid CreateMemberOpts (bad subnet_id, address not on the member subnet), quota exceeded for members, 409 immutable pool state across all retries, or 404 pool no longer exists.

Common situations: Node IP not in the subnet configured for the pool; subnet-id missing or wrong in the cluster LB config; Octavia quotas hit in shared projects; pool deleted concurrently by a cluster teardown.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/e55e0430bacb1cfb. Report an issue: GitHub.