microsoft/aspire · error · InvalidOperationException

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

Error message

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

What it means

A compute resource's workload identity is the exact same identity instance as the sandbox group's image-pull (AcrPull) identity. Granting AcrPull to that identity and also running workloads under it would expose registry pull permission to sandbox code, so publishing is blocked until a dedicated image-pull identity is provided.

Solutions

  1. Provision a separate user-assigned managed identity solely for image pulls and set it via the sandbox group's image-pull identity (AcrPull) configuration.
  2. Give the compute resource its own AzureUserAssignedIdentityResource distinct from the image-pull identity.
  3. Search your app model for the identity's resource name and confirm it appears in only one of the two roles (image pull vs workload).
  4. If simplification is the goal, remember the separation is a security boundary: the AcrPull identity must never run workload code.

Example fix

// before
var mi = new AzureUserAssignedIdentityResource("app-mi");
sandboxGroup.WithImagePullIdentity(mi);
compute.ConfigureAppIdentity(new AppIdentityAnnotation(mi));

// after
var pullMi = new AzureUserAssignedIdentityResource("acr-pull-mi");
var appMi = new AzureUserAssignedIdentityResource("app-mi");
sandboxGroup.WithImagePullIdentity(pullMi);
compute.ConfigureAppIdentity(new AppIdentityAnnotation(appMi));
Defensive patterns

Strategy: validation

Validate before calling

if (ReferenceEquals(pullIdentity, workloadIdentity))
{
    throw new InvalidOperationException("Image-pull identity must differ from every workload identity.");
}

Type guard

bool IsDedicatedPullIdentity(AzureUserAssignedIdentityResource pull, AzureUserAssignedIdentityResource workload) => !ReferenceEquals(pull, workload);

Try / catch

try { publish(); } catch (InvalidOperationException ex) when (ex.Message.Contains("for both image pulls and workload")) { /* create a dedicated AcrPull identity and reconfigure */ }

Prevention

When it happens

Trigger: Publishing when ReferenceEquals(imagePullIdentity, userAssignedIdentity) — the AzureSandboxGroupAcrPullIdentityAnnotation identity and the compute resource's AppIdentityAnnotation identity are the same AzureUserAssignedIdentityResource, and the sandbox group is not existing (the earlier existing-group check did not apply).

Common situations: Passing the same user-assigned identity to both the sandbox group's image-pull identity option and the workload's WithAppIdentity; constructing one identity resource and reusing it across sandbox-level and compute-level configuration to save a 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/a6b3ed7716be596c. Report an issue: GitHub.

Appendix: source

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

            }

            if (resource.TryGetLastAnnotation<AppIdentityAnnotation>(out var appIdentity))
            {
                if (appIdentity.IdentityResource is not AzureUserAssignedIdentityResource userAssignedIdentity)
                {
                    throw new NotSupportedException(
                        $"Compute resource '{resource.Name}' uses an application identity type that Azure sandboxes do not support.");
                }

                if (this.IsExisting())
                {
                    throw new InvalidOperationException(
                        $"Compute resource '{resource.Name}' uses managed identity '{userAssignedIdentity.Name}', but workload identities are not supported when publishing to existing Azure sandbox group '{Name}'.");
                }

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

                AddWorkloadUserAssignedIdentity(userAssignedIdentity);
            }

            AzureSandboxContainerDeployment.ValidateSandboxCompatibility(resource);

            resource.Annotations.Add(new ContainerBuildOptionsCallbackAnnotation(static buildOptions =>
            {
                // ADC requires a single Docker-format linux/amd64 manifest. Buildx's default OCI
                // index with provenance attestations can produce a disk image with no bootable root filesystem.
                buildOptions.Destination = ContainerImageDestination.Registry;
                buildOptions.OutputPath = null;
                buildOptions.ImageFormat = ContainerImageFormat.Docker;
                buildOptions.TargetPlatform = ContainerTargetPlatform.LinuxAmd64;
            }));

View on GitHub (pinned to 25830f84bd)