microsoft/aspire · error · DistributedApplicationException

Cannot create the cross-scope ACR pull identity

Error message

Cannot create the cross-scope ACR pull identity '{identityName}' for environment '{builder.Resource.Name}' because a resource with that name already exists. Call 'WithAcrPullIdentity' on the environment to select an existing identity, or use a different resource name.

What it means

When WithCrossScopeAcrPullIdentity needs to synthesize a managed identity, it derives the name '{environmentName}-mi' and throws DistributedApplicationException if an Azure resource with that name already exists in the model, because a cross-scope role assignment (BCP139) requires promoting this path to a standalone identity resource. The throw prevents silently attaching to an unrelated resource that happens to share the name.

Solutions

  1. Use WithAcrPullIdentity on the environment to reference the existing identity instead of creating a new one
  2. Rename the existing colliding resource (e.g. the manually created identity) so it no longer matches '{envName}-mi'
  3. Rename the environment resource itself so the derived '{name}-mi' is unique in the model
  4. Check for duplicate calls to WithCrossScopeAcrPullIdentity on the same-named environment and remove the redundant one

Example fix

// before
var env = builder.AddAzureEnvironment("prod");
env.WithCrossScopeAcrPullIdentity(); // throws if "prod-mi" already exists
// after
var existing = builder.AddAzureUserAssignedIdentity("prod-mi");
env.WithAcrPullIdentity(existing); // bind to the existing identity explicitly
Defensive patterns

Strategy: validation

Validate before calling

var identityName = $"{envBuilder.Resource.Name}-mi";
if (envBuilder.ApplicationBuilder.Resources.Any(r => string.Equals(r.Name, identityName, StringComparers.ResourceNameComparer)))
{
    // bind to the existing identity instead:
    envBuilder.WithAcrPullIdentity(existingIdentity);
}

Try / catch

try { envBuilder.WithCrossScopeAcrPullIdentity(); }
catch (DistributedApplicationException ex) { throw new InvalidOperationException("Name collision on derived identity; use WithAcrPullIdentity with an existing identity.", ex); }

Prevention

When it happens

Trigger: Calling WithCrossScopeAcrPullIdentity on an environment when the app model already contains a resource named '{environment.Resource.Name}-mi' — typically a user-defined identity, another environment with the same name plus '-mi', or a manually created AzureUserAssignedIdentityResource with the colliding name.

Common situations: Two environments in one AppHost generate the same '-mi' suffix name; the developer already created an identity named e.g. 'env-mi' for other purposes; a previous version of the call already added the identity and the code now runs twice.

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/273d62ebb2444398. Report an issue: GitHub.

Appendix: source

Thrown at src/Shared/CrossScopeAcrPullIdentityPreparer.cs:122

        PipelineStepContext context,
        IResourceBuilder<TEnvironment> builder,
        Func<AzureUserAssignedIdentityResource, IAcrPullIdentityAnnotation> createIdentityAnnotation,
        Action<IResourceBuilder<AzureUserAssignedIdentityResource>>? configureIdentity)
        where TEnvironment : IResource, IAzureComputeEnvironmentResource
    {
        if (!ShouldPrepareIdentity(context.ExecutionContext, builder.Resource) ||
            builder.Resource.ContainerRegistry is not AzureContainerRegistryResource registry)
        {
            return;
        }

        // A cross-scope role assignment cannot be emitted inline in the environment module (BCP139).
        // Promote only this path to a standalone identity so AzureResourcePreparer can emit the
        // role assignment as a module scoped to the existing registry.
        var identityName = $"{builder.Resource.Name}-mi";
        if (context.Model.Resources.TryGetByName(identityName, out _))
        {
            throw new DistributedApplicationException(
                $"Cannot create the cross-scope ACR pull identity '{identityName}' for environment '{builder.Resource.Name}' because a resource with that name already exists. Call 'WithAcrPullIdentity' on the environment to select an existing identity, or use a different resource name.");
        }

        var identity = new AzureUserAssignedIdentityResource(identityName);
        var identityBuilder = builder.ApplicationBuilder.CreateResourceBuilder(identity);
        identityBuilder.ConfigureInfrastructure(infrastructure =>
        {
            // The inline identity uses the environment module's standard tags parameter. Recreate that
            // contract on the promoted module so deployment tags and required-tag policies still apply.
            var tags = new ProvisioningParameter("tags", typeof(object))
            {
                Value = new BicepDictionary<string>()
            };
            infrastructure.Add(tags);

            var identity = infrastructure.GetProvisionableResources().OfType<UserAssignedIdentity>().Single();
            identity.Tags = tags;
        });

View on GitHub (pinned to 25830f84bd)