Skip to content

Regression in v0.11.4: Direct list comprehensions cause "multiple composed resources with same name" error #285

@irizzant

Description

@irizzant

What happened?

A regression was introduced in v0.11.4 that causes "multiple composed resources with same name" errors when using direct list comprehensions in KCL functions, even when the composition resource names are unique.

The error occurs when using patterns like:

_items += [Resource {...} for idx, s in someList]

This same code works correctly in v0.11.1 but fails in v0.11.4 with:

cannot compose resources: pipeline step "kcl" returned a fatal result: cannot process xr and state with the pipeline output in *v1beta1.RunFunctionResponse: duplicate resource names example-network-private-0 found, when returning multiple resources, you need to set different metadata.name or matadata.annotations."krm.kcl.dev/composition-resource-name" to distinguish between different resources in the composition functions.

How can we reproduce it?

Complete KCL Function Code:

import models.io.upbound.azure.network.v1beta1 as networkv1beta1

# Mock input parameters for reproduction
oxr = {
    spec = {
        parameters = {
            id = "example-network"
            subnets = [
                { type = "public", cidrBlock = "192.168.1.0/24", availabilityZone = "1" }
                { type = "public", cidrBlock = "192.168.2.0/24", availabilityZone = "2" }
                { type = "private", cidrBlock = "192.168.10.0/24", availabilityZone = "1" }
                { type = "private", cidrBlock = "192.168.11.0/24", availabilityZone = "2" }
            ]
        }
    }
}

parameters = oxr.spec.parameters
id = parameters.id

# Metadata function that generates UNIQUE composition resource names
_metadata = lambda id: str, kind: str, suffix: str -> any {
    {
        annotations = {
            if suffix == "":
                "krm.kcl.dev/composition-resource-name" = id + "-" + kind
            else:
                # This creates UNIQUE names like: example-network-subnet-public-0, example-network-subnet-public-1, etc.
                "krm.kcl.dev/composition-resource-name" = id + "-" + kind + "-" + suffix
        }
        name = id + (("-" + suffix) if suffix != "" else "")
    }
}

# This is the problematic code that works in v0.11.1 but fails in v0.11.4
subnets = parameters.subnets
publicSubnets = [s for s in subnets if s.type == "public"]
privateSubnets = [s for s in subnets if s.type == "private"]

_items: [any] = []

# These direct list comprehensions cause the bug in v0.11.4
_items += [networkv1beta1.Subnet {
    metadata = _metadata(id, "subnet", "public-${idx}") | {
        labels = {
            access = "public"
        }
    }
    spec = {
        forProvider = {
            addressPrefixes = [s.cidrBlock]
        }
    }
} for idx, s in publicSubnets]

_items += [networkv1beta1.Subnet {
    metadata = _metadata(id, "subnet", "private-${idx}") | {
        labels = {
            access = "private"
        }
    }
    spec = {
        forProvider = {
            addressPrefixes = [s.cidrBlock]
        }
    }
} for idx, s in privateSubnets]

items = _items

Expected Output (what v0.11.1 produces correctly):

The _metadata function generates these UNIQUE composition resource names:

  • example-network-subnet-public-0
  • example-network-subnet-public-1
  • example-network-subnet-private-0
  • example-network-subnet-private-1

Actual Error in v0.11.4:

Despite the composition resource names being provably unique, v0.11.4 throws:

duplicate resource names example-network-subnet-private-0 found

Proof that Names are Unique:

You can verify the uniqueness by adding debug output:

# Add this to see the unique names being generated
publicSubnetNames = [_metadata(id, "subnet", "public-${idx}").annotations["krm.kcl.dev/composition-resource-name"] for idx, s in publicSubnets]
privateSubnetNames = [_metadata(id, "subnet", "private-${idx}").annotations["krm.kcl.dev/composition-resource-name"] for idx, s in privateSubnets]

# This will show: ["example-network-subnet-public-0", "example-network-subnet-public-1", "example-network-subnet-private-0", "example-network-subnet-private-1"]
# All names are unique!

What environment did it happen in?

  • Function version: v0.11.4
  • Working version: v0.11.1
  • Platform: Crossplane network composition functions

Root Cause Analysis

The _metadata function IS generating unique names. The bug is that v0.11.4's duplicate detection logic is incorrectly flagging unique resources as duplicates when they're created through direct list comprehensions.

The regression appears to be related to changes made between v0.11.1 and v0.11.4, likely connected to the duplicate name detection added in PR #253. The error detection logic seems to be incorrectly flagging legitimate resources with unique names as duplicates when they're generated through direct list comprehensions.

Workarounds

Two workarounds are available:

Option 1: Use intermediate variables (works with v0.11.4)

# Store results in intermediate variables first
publicSubnetResources = [Subnet {
    metadata = _metadata(id, "subnet", "public-${idx}")
    # ... rest of configuration
} for idx, s in publicSubnets]

privateSubnetResources = [Subnet {
    metadata = _metadata(id, "subnet", "private-${idx}")  
    # ... rest of configuration
} for idx, s in privateSubnets]

# Then add to _items
_items += publicSubnetResources
_items += privateSubnetResources

Option 2: Downgrade to v0.11.1

# In providers/functions.yaml
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
  name: kcl-function
spec:
  package: xpkg.upbound.io/crossplane-contrib/function-kcl:v0.11.1

Additional Context

  • This regression affects real-world compositions that were working correctly before
  • AWS compositions using similar patterns work because they likely use an older function version
  • The error suggests duplicate names even when krm.kcl.dev/composition-resource-name annotations are demonstrably unique
  • This is similar to the regression reported in issue Multiple resources #125 for v0.9.2

Related Issues

This regression breaks existing working compositions and should be prioritized for fixing in the next release.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions