microsoft/aspire · error · InvalidOperationException

Resource ' ' maps multiple distinct sources named ' ' to…

Error message

Resource '{TargetResource.Name}' maps multiple distinct {sourceKind} sources named '{parameter.Name}' to Helm values path '{helmKey}.{resourceKey}.{valuesKey}'. Reuse the same ParameterResource instance or give each source a unique name.

What it means

Thrown by AddParameterMapping in KubernetesResource when two distinct ParameterResource instances with the same name would map to the same Helm values path '{helmKey}.{resourceKey}.{valuesKey}'. The publisher requires that each Helm values path is backed by exactly one parameter instance so conditional/expression resolution is deterministic.

Solutions

  1. Reuse the same ParameterResource instance everywhere instead of creating a second one with the same name
  2. Give each distinct source a unique parameter name
  3. Set an explicit unique ValuesKey on the Helm value mapping for one of the sources
  4. Search the app model for duplicate AddParameter calls with the colliding name

Example fix

// before
var p1 = builder.AddParameter("conn");
var p2 = builder.AddParameter("conn"); // distinct instance, same name
resource.WithReference(expr1(p1));
resource.WithReference(expr2(p2));
// after
var p = builder.AddParameter("conn");
resource.WithReference(expr1(p));
resource.WithReference(expr2(p)); // reuse the same instance
Defensive patterns

Strategy: validation

Validate before calling

var dupes = parameters.GroupBy(p => p.Name).Where(g => g.Count() > 1 && g.Select(x => x).Distinct().Count() > 1).ToList();
if (dupes.Any()) throw new InvalidOperationException($"Distinct parameters share names: {string.Join(",", dupes.Select(d => d.Key))}");

Try / catch

try { PublishAsync(...); }
catch (InvalidOperationException ex) when (ex.Message.Contains("maps multiple distinct")) { /* deduplicate parameter instances */ }

Prevention

When it happens

Trigger: BuildHelmConditional or AllocateAdditionalParameter registering a second, non-identical ParameterResource whose name (or ValuesKey) collides with a previously mapped parameter for the same target resource.

Common situations: Creating two separate builder.AddParameter("name") calls in different places with the same name and passing both into expressions; deserialization or cloning producing distinct ParameterResource instances that share a name; conditional expressions pulling in a same-named parameter from a different resource.

Understand the failure class

Background: Conflicting config options: "cannot be used together" — configuration validation errors across open-source libraries — this error's family across 162 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/0e43a131f4fe6cc6. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Kubernetes/KubernetesResource.cs:741

        ParameterResource parameter,
        HelmValue helmValue,
        string helmKey,
        string sourceKind)
    {
        if (!mappings.TryGetValue(parameter.Name, out var existing))
        {
            mappings.Add(parameter.Name, helmValue);
            return;
        }

        if (ReferenceEquals(existing.ParameterSource, parameter))
        {
            return;
        }

        var resourceKey = TargetResource.Name.ToHelmValuesSectionName();
        var valuesKey = helmValue.ValuesKey ?? parameter.Name.ToHelmValuesSectionName();
        throw new InvalidOperationException(
            $"Resource '{TargetResource.Name}' maps multiple distinct {sourceKind} sources named '{parameter.Name}' " +
            $"to Helm values path '{helmKey}.{resourceKey}.{valuesKey}'. Reuse the same ParameterResource instance " +
            "or give each source a unique name.");
    }

    private static string GetEndpointValue(EndpointMapping mapping, EndpointProperty property, bool embedded = false)
    {
        var (scheme, _, host, targetPort, _, _, exposedPort) = mapping;

        // In Kubernetes a Service publishes `port` and forwards traffic to the pod's `targetPort`.
        // Other resources reach this resource through the Service, so the client-facing address must
        // use the Service (exposed) port, not the container's listening port. When no distinct
        // exposed port was configured (`port == targetPort`, or the deployment tool assigns it),
        // ServicePort is null and we fall back to the target port. Only EndpointProperty.TargetPort
        // surfaces the container's listening port. This mirrors the Azure Container Apps publisher.
        // See: https://github.com/microsoft/aspire/issues/18321
        var servicePort = exposedPort ?? targetPort;

View on GitHub (pinned to 25830f84bd)