microsoft/aspire · error · InvalidOperationException

Azure sandbox group ' ' uses identity ' ' for both image…

Error message

Azure sandbox group '{Name}' uses identity '{imagePullIdentity.Name}' for both image pulls and workloads. Use a dedicated image-pull identity so its AcrPull permission is not exposed to sandbox workloads.

What it means

The identity designated for pulling container images from the registry (with AcrPull) is also listed as a workload identity of the sandbox group. Because workload code could run under that identity and gain registry pull (and potentially sensitive registry) access, the library refuses to publish until a dedicated image-pull identity is used.

Solutions

  1. Create a separate user-assigned managed identity exclusively for image pulls and configure it as the sandbox group's AcrPull identity.
  2. Ensure each compute resource's app identity is a distinct identity not referenced by the AzureSandboxGroupAcrPullIdentityAnnotation.
  3. Audit your publish model for identity reuse: list the sandbox group's image-pull identity and every workload identity and confirm there is no overlap.
  4. If using an existing identity everywhere, provision a second identity and grant only it the AcrPull role on the registry.

Example fix

// before
var shared = new AzureUserAssignedIdentityResource("shared-mi");
sandboxGroup.WithImagePullIdentity(shared);
compute.WithAppIdentity(shared);

// after
var pullIdentity = new AzureUserAssignedIdentityResource("acr-pull-mi");
sandboxGroup.WithImagePullIdentity(pullIdentity);
compute.WithAppIdentity(new AzureUserAssignedIdentityResource("workload-mi"));
Defensive patterns

Strategy: validation

Validate before calling

var pull = sandboxGroup.GetImagePullIdentity(); // via AzureSandboxGroupAcrPullIdentityAnnotation
if (pull is not null && sandboxGroup.WorkloadUserAssignedIdentities.Contains(pull))
{
    throw new InvalidOperationException("Image-pull identity must be distinct from workload identities.");
}

Type guard

var pullIdentity = resource.TryGetLastAnnotation<AzureSandboxGroupAcrPullIdentityAnnotation>(out var a) ? a.Identity : null;

Try / catch

try { publish(); } catch (InvalidOperationException ex) when (ex.Message.Contains("for both image pulls and workloads")) { /* provision a dedicated AcrPull identity and update options */ }

Prevention

When it happens

Trigger: Publishing when the AzureSandboxGroupAcrPullIdentityAnnotation identity is contained in WorkloadUserAssignedIdentities — e.g. the same user-assigned managed identity was supplied both as the AcrPull identity (via the sandbox group's image-pull identity configuration) and as the app identity of a compute resource.

Common situations: Reusing one managed identity for everything in the sandbox group to simplify setup; copying the same identity resource into PublishAsAzureSandbox identity options and the compute resource's WithAppIdentity/ConfigureAppIdentity; sharing a pre-existing identity across sandbox-level and workload-level configuration.

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/91e380eec191fead. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.Azure.Sandboxes/AzureSandboxGroupResource.cs:205

            return;
        }

        if (this.HasAnnotationOfType<ContainerRegistryReferenceAnnotation>() &&
            DefaultContainerRegistry is not null)
        {
            context.Model.Resources.Remove(DefaultContainerRegistry);
            DefaultContainerRegistry = null;
        }

        var containerRegistry = ContainerRegistry ??
            throw new InvalidOperationException($"No container registry associated with Azure sandbox group '{Name}'. This should have been added automatically.");
        var imagePullIdentity = this.TryGetLastAnnotation<AzureSandboxGroupAcrPullIdentityAnnotation>(out var imagePullIdentityAnnotation)
            ? imagePullIdentityAnnotation.Identity
            : null;

        if (imagePullIdentity is not null && WorkloadUserAssignedIdentities.Contains(imagePullIdentity))
        {
            throw new InvalidOperationException(
                $"Azure sandbox group '{Name}' uses identity '{imagePullIdentity.Name}' for both image pulls and workloads. " +
                "Use a dedicated image-pull identity so its AcrPull permission is not exposed to sandbox workloads.");
        }

        var computeEnvironments = context.Model.Resources.OfType<IComputeEnvironmentResource>().ToList();
        var canClaimUnassignedComputeResources = computeEnvironments.Count == 1 && ReferenceEquals(computeEnvironments[0], this);

        foreach (var resource in context.Model.GetComputeResources())
        {
            var resourceComputeEnvironment = resource.GetComputeEnvironment();
            if (resourceComputeEnvironment is null && !canClaimUnassignedComputeResources)
            {
                continue;
            }

            if (resourceComputeEnvironment is not null && resourceComputeEnvironment != this)
            {
                continue;

View on GitHub (pinned to 25830f84bd)