cilium/cilium · error

DeleteIpamIPFailureCode

DeleteIpamIPFailureCode

Error message

IP is in use by endpoint %d

What it means

The DELETE /ipam/IP handler refuses to release an IP currently assigned to an endpoint. It checks EndpointManager.LookupIPv4/LookupIPv6 first and returns a DeleteIpamIPFailureCode API error naming the owning endpoint ID.

Source

Thrown at pkg/ipam/api/ipam_api_handler.go:141

	return nodeRouterAddressing, nil
}

// Handle incoming address allocation requests for the daemon.
func (r *IpamPostIpamIPHandler) Handle(params ipamapi.PostIpamIPParams) middleware.Responder {
	owner := swag.StringValue(params.Owner)
	pool := ipam.Pool(swag.StringValue(params.Pool))
	if err := r.IPAM.AllocateIPString(params.IP, owner, pool); err != nil {
		return api.Error(ipamapi.PostIpamIPFailureCode, err)
	}

	return ipamapi.NewPostIpamIPOK()
}

func (r *IpamDeleteIpamIPHandler) Handle(params ipamapi.DeleteIpamIPParams) middleware.Responder {
	// Release of an IP that is in use is not allowed
	if ep := r.EndpointManager.LookupIPv4(params.IP); ep != nil {
		return api.Error(ipamapi.DeleteIpamIPFailureCode, fmt.Errorf("IP is in use by endpoint %d", ep.ID))
	}
	if ep := r.EndpointManager.LookupIPv6(params.IP); ep != nil {
		return api.Error(ipamapi.DeleteIpamIPFailureCode, fmt.Errorf("IP is in use by endpoint %d", ep.ID))
	}

	ip, err := netip.ParseAddr(params.IP)
	if err != nil {
		return api.Error(ipamapi.DeleteIpamIPInvalidCode, fmt.Errorf("Invalid IP address %s: %w", params.IP, err))
	}

	pool := ipam.Pool(swag.StringValue(params.Pool))
	if err := r.IPAM.ReleaseIP(ip, pool); err != nil {
		return api.Error(ipamapi.DeleteIpamIPFailureCode, err)
	}

	return ipamapi.NewDeleteIpamIPOK()
}

View on GitHub (pinned to ac7b90affa)

Solutions

  1. Release the IP only after the owning endpoint is deleted (delete the pod or wait for termination to complete)
  2. Verify the endpoint ID in the error and confirm whether it is truly stale; remove the endpoint via the API if it is orphaned
  3. Find a different free IP if you only need a replacement address

Example fix

// before
curl -X DELETE .../ipam/IP?ip=10.0.1.5  # fails: in use by endpoint 1234
// after
# 1) remove/confirm the endpoint is gone
kubectl delete pod my-pod   # or wait for its CNI DELETE to complete
# 2) then release the IP
curl -X DELETE .../ipam/IP?ip=10.0.1.5
Defensive patterns

Strategy: try-catch

Validate before calling

// Client-side check before DELETE (approximate):
// list endpoints and ensure none uses the IP
func ipInUse(eps []EndpointInfo, ip string) bool {
    for _, e := range eps {
        if e.IPv4 == ip || e.IPv6 == ip { return true }
    }
    return false
}

Try / catch

resp, err := client.DeleteIpamIP(ip)
if err != nil && strings.Contains(err.Error(), "IP is in use by endpoint") {
    return skipOrDeleteEndpointFirst(ip) // parse endpoint ID from message
}
return err

Prevention

When it happens

Trigger: DELETE /ipam/IP for an IP bound to a running pod/endpoint; operators cleaning up 'stale' IPs that are actually in use; releasing an IP while its endpoint is terminating but not yet removed.

Common situations: Manual cleanup scripts freeing pod CIDR IPs that collide with live workloads; buggy controllers double-releasing IPs; CNI DELETE racing endpoint teardown.

Related errors


AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31). Data as JSON: /api/errors/ec687804bce079fd. Report an issue: GitHub.