microsoft/aspire · error · ArgumentException

A security rule named

Error message

A security rule named '{rule.Name}' already exists in Network Security Group '{builder.Resource.Name}'.

What it means

WithSecurityRule adds a security rule to an Azure Network Security Group resource. Aspire rejects duplicate rule names (case-insensitive comparison) with ArgumentException because NSG security rules must be uniquely named within the NSG.

Solutions

  1. Rename one of the rules so names are unique within the NSG.
  2. Make generated names unique by appending an index or port, e.g. $"allow-{port}".
  3. Check for duplicate WithSecurityRule calls in loops or helper methods.
  4. Pre-check with builder.Resource.SecurityRules before adding if names are dynamic.

Example fix

// before
nsg.WithSecurityRule(new SecurityRule { Name = "allow-http", ... });
nsg.WithSecurityRule(new SecurityRule { Name = "Allow-HTTP", ... });
// after
nsg.WithSecurityRule(new SecurityRule { Name = "allow-http", ... });
nsg.WithSecurityRule(new SecurityRule { Name = "allow-https", ... });
Defensive patterns

Strategy: validation

Validate before calling

if (builder.Resource.SecurityRules.Any(r => string.Equals(r.Name, rule.Name, StringComparison.OrdinalIgnoreCase)))
    throw new ArgumentException($"Rule '{rule.Name}' already exists in NSG '{builder.Resource.Name}'.");

Try / catch

try { nsgBuilder.WithSecurityRule(rule); }
catch (ArgumentException ex) when (ex.Message.Contains("already exists")) { /* skip or rename the duplicate rule */ }

Prevention

When it happens

Trigger: Calling WithSecurityRule twice on the same NSG builder with rules whose Name properties are equal ignoring case, e.g. 'allow-http' and 'Allow-HTTP'.

Common situations: Loop-driven rule setup where names are generated with the same template, copy-pasted rule definitions, or conditional calls that both add a rule with a shared constant name.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Azure.Network/AzureNetworkSecurityGroupExtensions.cs:101

    ///         Direction = SecurityRuleDirection.Inbound,
    ///         Access = SecurityRuleAccess.Deny,
    ///         Protocol = SecurityRuleProtocol.Asterisk,
    ///         DestinationPortRange = "*"
    ///     });
    /// </code>
    /// </example>
    [AspireExport]
    public static IResourceBuilder<AzureNetworkSecurityGroupResource> WithSecurityRule(
        this IResourceBuilder<AzureNetworkSecurityGroupResource> builder,
        AzureSecurityRule rule)
    {
        ArgumentNullException.ThrowIfNull(builder);
        ArgumentNullException.ThrowIfNull(rule);
        ArgumentException.ThrowIfNullOrEmpty(rule.Name);

        if (builder.Resource.SecurityRules.Any(existing => string.Equals(existing.Name, rule.Name, StringComparison.OrdinalIgnoreCase)))
        {
            throw new ArgumentException(
                $"A security rule named '{rule.Name}' already exists in Network Security Group '{builder.Resource.Name}'.",
                nameof(rule));
        }

        builder.Resource.SecurityRules.Add(rule);
        return builder;
    }

    private static void ConfigureNetworkSecurityGroup(AzureResourceInfrastructure infra)
    {
        var azureResource = (AzureNetworkSecurityGroupResource)infra.AspireResource;

        var nsg = AzureProvisioningResource.CreateExistingOrNewProvisionableResource(infra,
            (identifier, name) =>
            {
                var resource = NetworkSecurityGroup.FromExisting(identifier);
                resource.Name = name;
                return resource;

View on GitHub (pinned to 25830f84bd)