Managed resource selector only picks up some of the matching resources (e.g. ElastiCache UserGroup userIdSelector)
Last updated: September 30, 2026
Issue
A managed resource that uses a selector to reference multiple other resources only includes some of the resources that match the selector. The resource is Ready=True and Synced=True and no error is reported. The behavior is intermittent. Most of the time all matching resources are picked up, but occasionally one or more are missing.
Example: an ElastiCache UserGroup with a userIdSelector using matchControllerRef: true and a label selector includes only one of three matching User resources in spec.forProvider.userIds and status.atProvider.userIds, even though all three User resources carry the correct labels and belong to the same composite.
The same behavior applies to any multi-reference selector, for example subnetIdSelector or securityGroupIdSelector.
Environment
Crossplane managed resources that use a multi-reference selector (
<field>Selector)Referencing and referenced resources created at the same time, typically from the same composition
Selector without a
policyfield (defaultIfNotPresent)
Resolution
Add policy.resolve: Always to the selector in the composition or composition function that builds the resource:
userIdSelector:
matchControllerRef: true
matchLabels:
example.com/resource-type: user
policy:
resolve: AlwaysIf the resource is rendered by a composition function, make the change in the function code. Editing the live object is not enough, because it is overwritten on the next compose.
Once this change is applied, existing resources re-evaluate the selector on the next reconcile and pick up all matching resources. New resources are no longer affected.
Note: With resolve: Always, if a referenced resource is deleted or its matching label is removed, it is also removed from the list on the next reconcile.
One-time alternative: clear the resolved fields (for example spec.forProvider.userIds and spec.forProvider.userIdRefs) on the affected resource. The selector runs once more, but the issue can recur on new resources.
Cause
By default, selectors use the IfNotPresent resolve policy. Under this policy, the selector is only evaluated while both the value field (e.g. userIds) and the refs field (e.g. userIdRefs) are empty. Once those fields are populated, the resolved values are treated as cached and the selector is not evaluated again.
When the referencing resource and the referenced resources are created at nearly the same time, the selector can be resolved before all referenced resources are visible. Only the resources visible at that moment are selected, and any that become visible afterwards are never added.
To confirm this is the cause:
The value and refs fields contain fewer entries than the number of resources that match the selector.
In
metadata.managedFields, the managermanaged.crossplane.io/api-simple-reference-resolverwrote those fields at, or very close to, the resource'screationTimestamp.The selector has no
policyfield set.
The policy.resolve option was introduced in crossplane-runtime v0.17.0 and is available in all providers built on that version or later, which includes all current Upbound official providers.
Related
crossplane-runtime issue #250 — Selector race condition with IfNotPresent policy
crossplane-runtime PR #328 — Introduced the policy field for references and selectors