What's Actually Happening
Crossplane composite resource (XR) fails to create or reconcile. Infrastructure resources are not provisioned as expected.
The Error You'll See
```bash $ kubectl get composite.myorg.io
NAME READY COMPOSITION AGE my-resource false my-composition 5m
$ kubectl describe composite my-resource Status: Conditions: Type: Ready Status: False Reason: CompositionNotFound ```
Composition error:
Error: composition "my-composition" not foundProvider error:
Error: no matching provider config for claimClaim binding failed:
Error: cannot bind claim to composite: resource version mismatchWhy This Happens
- 1.Composition not found - Composition definition missing
- 2.Wrong composition selector - Label selector not matching
- 3.Provider config missing - ProviderConfig not defined
- 4.Claim namespace mismatch - Claim in wrong namespace
- 5.Missing XRD definition - CompositeResourceDefinition not installed
- 6.Provider not installed - Crossplane provider package missing
Step 1: Check Composite Resource Status
```bash # List composite resources: kubectl get composite -A
# Get specific composite: kubectl get composite.myorg.io my-resource -o yaml
# Describe composite: kubectl describe composite.myorg.io my-resource
# Check conditions: kubectl get composite.myorg.io my-resource -o jsonpath='{.status.conditions}'
# Check composition reference: kubectl get composite.myorg.io my-resource -o jsonpath='{.spec.compositionRef}'
# Check composed resources: kubectl get composite.myorg.io my-resource -o jsonpath='{.status.resourceRefs}'
# View events: kubectl get events --field-selector involvedObject.name=my-resource
# Check composite claim: kubectl get claim -A kubectl get myresource.myorg.io -n default my-claim -o yaml ```
Step 2: Verify Composition Definition
```bash # List compositions: kubectl get composition -A
# Check composition exists: kubectl get composition my-composition -o yaml
# Describe composition: kubectl describe composition my-composition
# Check composition selector: kubectl get composition my-composition -o jsonpath='{.spec.compositeTypeRef}' # Must match XR type
# Check environment templates: kubectl get composition my-composition -o yaml | grep -A5 "environment"
# Verify patch sets: kubectl get composition my-composition -o yaml | grep -A10 "patches"
# Check composition revision: kubectl get compositionrevision
# Create composition if missing: apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: my-composition spec: compositeTypeRef: apiVersion: myorg.io/v1 kind: MyComposite resources: - base: apiVersion: aws.crossplane.io/v1 kind: S3Bucket spec: forProvider: region: us-east-1 patches: - fromFieldPath: spec.parameters.bucketName toFieldPath: spec.forProvider.bucket ```
Step 3: Check CompositeResourceDefinition
```bash # List XRDs: kubectl get xrd
# Check XRD exists: kubectl get xrd mycomposite.myorg.io -o yaml
# Describe XRD: kubectl describe xrd mycomposite.myorg.io
# Check XRD generates CRDs: kubectl get crd | grep myorg.io
# Check claim CRD created: kubectl get crd myresources.myorg.io
# Verify claim namespaced: kubectl get crd myresources.myorg.io -o jsonpath='{.spec.scope}' # Should be Namespaced
# Create XRD if missing: apiVersion: apiextensions.crossplane.io/v1 kind: CompositeResourceDefinition metadata: name: mycomposites.myorg.io spec: group: myorg.io names: kind: MyComposite plural: mycomposites claimNames: kind: MyResource plural: myresources versions: - name: v1 served: true referenceable: true schema: openAPIV3Schema: type: object properties: spec: type: object properties: parameters: type: object properties: bucketName: type: string ```
Step 4: Check Provider Configuration
```bash # List Crossplane providers: kubectl get pkg -A
# Check provider installed: kubectl get provider
# Verify provider revision: kubectl get providerrevision
# Check provider pods: kubectl get pods -n crossplane-system | grep provider
# List ProviderConfigs: kubectl get providerconfig -A
# Check specific ProviderConfig: kubectl get providerconfig.aws my-config -o yaml
# Describe ProviderConfig: kubectl describe providerconfig.aws my-config
# Create ProviderConfig: apiVersion: aws.crossplane.io/v1 kind: ProviderConfig metadata: name: my-config spec: credentials: source: Secret secretRef: namespace: crossplane-system name: aws-creds key: creds
# Check credentials secret: kubectl get secret -n crossplane-system aws-creds
# Verify credentials: kubectl get secret aws-creds -n crossplane-system -o jsonpath='{.data.creds}' | base64 -d ```
Step 5: Check Claim Binding
```bash # List claims: kubectl get claim -A kubectl get myresource.myorg.io -A
# Check claim status: kubectl get myresource.myorg.io my-claim -n default -o yaml
# Check claim binding: kubectl get myresource.myorg.io my-claim -n default -o jsonpath='{.status.claimConditionTypes}'
# View composite reference: kubectl get myresource.myorg.io my-claim -n default -o jsonpath='{.spec.resourceRef}'
# Check claim to composite binding: kubectl get composite.myorg.io -A -o yaml | grep claimRef
# Verify namespace matches: kubectl get myresource.myorg.io my-claim -n default kubectl get composite.myorg.io my-resource -n crossplane-system
# Check claim class: kubectl get myresource.myorg.io my-claim -n default -o jsonpath='{.spec.compositionSelector}'
# Force claim binding by recreating: kubectl delete myresource.myorg.io my-claim -n default kubectl apply -f claim.yaml ```
Step 6: Check Composition Selector Matching
```bash # Check composite labels: kubectl get composite.myorg.io my-resource --show-labels
# Check composition selector in claim: kubectl get myresource.myorg.io my-claim -o jsonpath='{.spec.compositionSelector}'
# Verify labels match: # Claim selector: # matchLabels: # environment: production
# Composition must have: # metadata: # labels: # environment: production
# Add labels to composition: kubectl label composition my-composition environment=production
# Or update claim selector: apiVersion: myorg.io/v1 kind: MyResource metadata: name: my-claim spec: compositionSelector: matchLabels: environment: production parameters: bucketName: my-bucket
# Check composition mode: kubectl get composition my-composition -o jsonpath='{.spec.mode}' # Pipeline or Resources ```
Step 7: Debug Composed Resources
```bash # List composed resources: kubectl get managed -A
# Check specific managed resource: kubectl get s3bucket.aws.crossplane.io -A
# Check resource status: kubectl get s3bucket.aws.crossplane.io my-bucket -o yaml
# Check resource conditions: kubectl get s3bucket.aws.crossplane.io my-bucket -o jsonpath='{.status.conditions}'
# Check for provider errors: kubectl describe s3bucket.aws.crossplane.io my-bucket
# View connection details: kubectl get s3bucket.aws.crossplane.io my-bucket -o jsonpath='{.status.atProvider}'
# Check resource bindings: kubectl get secret -A | grep my-bucket
# Verify connection secret: kubectl get secret my-bucket-connection -n default ```
Step 8: Check Crossplane Controller
```bash # Check Crossplane pods: kubectl get pods -n crossplane-system
# View Crossplane logs: kubectl logs -n crossplane-system deploy/crossplane
# Check provider logs: kubectl logs -n crossplane-system provider-aws-xxx
# Check recent events: kubectl get events -n crossplane-system --sort-by='.lastTimestamp'
# Check Crossplane resources: kubectl top pods -n crossplane-system
# Check Crossplane RBAC: kubectl get clusterrole | grep crossplane kubectl get clusterrolebinding | grep crossplane
# Restart Crossplane: kubectl rollout restart deploy/crossplane -n crossplane-system
# Restart provider: kubectl rollout restart deploy/provider-aws -n crossplane-system ```
Step 9: Test Composition Pipeline
```bash # Enable debug logging: kubectl set env deploy/crossplane -n crossplane-system LOG_LEVEL=debug
# Apply claim: kubectl apply -f claim.yaml
# Watch composite creation: kubectl get composite.myorg.io -w
# Check composition revision: kubectl get compositionrevision my-composition-xxx -o yaml
# Verify function pipeline: kubectl get composition my-composition -o yaml | grep -A20 "pipeline"
# Test with minimal composition: apiVersion: apiextensions.crossplane.io/v1 kind: Composition metadata: name: test-composition spec: compositeTypeRef: apiVersion: myorg.io/v1 kind: MyComposite resources: - base: apiVersion: kubernetes.crossplane.io/v1 kind: Object spec: forProvider: manifest: apiVersion: v1 kind: ConfigMap metadata: namespace: default patches: - fromFieldPath: metadata.name toFieldPath: spec.forProvider.manifest.metadata.name ```
Step 10: Crossplane Verification Script
```bash # Create verification script: cat << 'EOF' > /usr/local/bin/check-crossplane.sh #!/bin/bash
XR=${1:-"my-resource"} KIND=${2:-"composite.myorg.io"}
echo "=== Crossplane Pods ===" kubectl get pods -n crossplane-system
echo "" echo "=== Providers ===" kubectl get provider
echo "" echo "=== ProviderConfigs ===" kubectl get providerconfig -A
echo "" echo "=== CompositeResourceDefinitions ===" kubectl get xrd
echo "" echo "=== Compositions ===" kubectl get composition
echo "" echo "=== Composite Resource Status ===" kubectl get $KIND $XR -o yaml | grep -A20 "status:"
echo "" echo "=== Claim Status ===" kubectl get claim -A | head -10
echo "" echo "=== Composed Resources ===" kubectl get managed -A | head -20
echo "" echo "=== Events ===" kubectl get events -n crossplane-system --sort-by='.lastTimestamp' | tail -10
echo "" echo "=== Crossplane Logs ===" kubectl logs -n crossplane-system deploy/crossplane --tail=20 | grep -i "composite|composition|error"
echo "" echo "=== Recommendations ===" echo "1. Verify composition exists and matches XR type" echo "2. Check composition selector labels match" echo "3. Ensure ProviderConfig exists with credentials" echo "4. Install required provider package" echo "5. Create CompositeResourceDefinition" echo "6. Check claim namespace and binding" echo "7. Review composed resource status" EOF
chmod +x /usr/local/bin/check-crossplane.sh
# Usage: /usr/local/bin/check-crossplane.sh my-resource composite.myorg.io ```
Crossplane Composite Resource Checklist
| Check | Expected |
|---|---|
| XRD installed | CRDs generated |
| Composition exists | Matches XR typeRef |
| Provider installed | Provider package present |
| ProviderConfig created | Credentials configured |
| Claim namespace | Matches claim scope |
| Selector labels | Composition matched |
| Composed resources | Managed resources created |
Verify the Fix
```bash # After fixing Crossplane composite resource
# 1. Check composite status kubectl get composite.myorg.io my-resource // READY: true
# 2. Verify composition ref kubectl get composite.myorg.io my-resource -o yaml // compositionRef.name: my-composition
# 3. Check composed resources kubectl get managed -A // Resources created
# 4. Verify claim binding kubectl get myresource.myorg.io my-claim -n default // READY: true
# 5. Check ProviderConfig kubectl get providerconfig.aws my-config // READY: true
# 6. Test connection secret kubectl get secret my-bucket-connection -n default // Secret created ```
Related Issues
- [Fix Kubernetes Deployment Not Working](/articles/fix-kubernetes-deployment-not-working)
- [Fix Terraform Provider Authentication Failed](/articles/fix-terraform-provider-authentication-failed)
- [Fix Helm Chart Installation Failed](/articles/fix-helm-chart-installation-failed)