microsoft/aspire · error · InvalidOperationException
Existing Azure sandbox group
Error message
Existing Azure sandbox group '{sandboxGroup.Name}' requires a user-assigned ACR pull identity. Call 'WithAcrPullIdentity' with an identity that is already attached to the sandbox group and has AcrPull on the configured registry. What it means
AddAzureSandboxGroup requires that existing (non-Aspire-managed) Azure sandbox groups supply a user-assigned ACR pull identity via WithAcrPullIdentity. When an AcrPull identity annotation exists but is Aspire-managed or references a non-existing identity resource, the extension throws because Aspire cannot attach a new managed identity to a group it does not own. The identity must already be attached to the sandbox group and have AcrPull on the registry.
Solutions
- Call WithAcrPullIdentity with an existing user-assigned identity already attached to the sandbox group.
- Grant that identity the AcrPull role on the configured container registry.
- Verify the identity passed is marked existing (Identity.IsExisting() == true), not a new Aspire-managed identity.
- If the group can be Aspire-managed instead, drop AsExisting so Aspire provisions and attaches the identity itself.
Example fix
// before (new/managed identity on an existing group)
var group = builder.AddAzureSandboxGroup("group", existing).WithAcrPullIdentity(newIdentity);
// after
var existingIdentity = builder.AddUserAssignedIdentity("acrPullIdentity").AsExisting(identityId, clientId);
var group = builder.AddAzureSandboxGroup("group", existing)
.WithAcrPullIdentity(existingIdentity); // already attached + AcrPull granted Defensive patterns
Strategy: validation
Validate before calling
// before AddAzureSandboxGroup on an existing group, ensure the identity is existing
var identityOk = sandboxResource.IsExisting()
&& sandboxResource.TryGetLastAnnotation<AzureSandboxGroupAcrPullIdentityAnnotation>(out var a)
&& !a.IsAspireManaged
&& a.Identity.IsExisting();
if (sandboxResource.IsExisting() && !identityOk)
{
// call WithAcrPullIdentity with an existing attached identity first
} Type guard
static bool HasValidExistingPullIdentity(IResource sandbox) =>
sandbox.TryGetLastAnnotation<AzureSandboxGroupAcrPullIdentityAnnotation>(out var a)
&& !a.IsAspireManaged
&& a.Identity.IsExisting(); Try / catch
try
{
var group = builder.AddAzureSandboxGroup("group", existing);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("ACR pull identity"))
{
// reconfigure with an existing identity attached to the group, then retry
} Prevention
- Always pair AsExisting sandbox groups with WithAcrPullIdentity(existingIdentity).
- Grant AcrPull on the registry to the identity before wiring it in.
- Attach the identity to the sandbox group outside Aspire; Aspire will not attach it for existing groups.
- Prefer Aspire-managed groups when you want Aspire to provision the pull identity.
When it happens
Trigger: AddAzureSandboxGroup on a sandbox resource where sandboxResource.IsExisting() is true and the AzureSandboxGroupAcrPullIdentityAnnotation is IsAspireManaged == true or its Identity.IsExisting() is false.
Common situations: Configuring an existing sandbox group but letting Aspire create a new user-assigned identity for ACR pull; using the default managed identity path against a pre-existing group; passing an identity resource that is newly created rather than the existing attached one.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- AppHost:DeploymentStatePathSha256 is required to isolate…
- Azure sandbox deployment state for resource
- Azure sandbox endpoint
- Azure sandbox group ' ' returned an invalid resource ID ' '.
- Cannot create the cross-scope ACR pull identity
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/d1c84ebfa5fd06c9.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.Azure.Sandboxes/AzureSandboxesExtensions.cs:58
[AspireExport]
[Experimental("ASPIREAZURE001", UrlFormat = "https://aka.ms/aspire/diagnostics/{0}")]
public static IResourceBuilder<AzureSandboxGroupResource> AddAzureSandboxGroup(this IDistributedApplicationBuilder builder, [ResourceName] string name)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentException.ThrowIfNullOrWhiteSpace(name);
static void ConfigureInfrastructure(AzureResourceInfrastructure infrastructure)
{
var sandboxResource = (AzureSandboxGroupResource)infrastructure.AspireResource;
UserAssignedIdentity? newImagePullIdentity = null;
BicepValue<string> imagePullIdentityId;
BicepValue<string> imagePullIdentityClientId;
if (sandboxResource.TryGetLastAnnotation<AzureSandboxGroupAcrPullIdentityAnnotation>(out var imagePullIdentityAnnotation))
{
if (sandboxResource.IsExisting() &&
(imagePullIdentityAnnotation.IsAspireManaged || !imagePullIdentityAnnotation.Identity.IsExisting()))
{
throw CreateExistingSandboxGroupMissingAcrPullIdentityException(sandboxResource);
}
imagePullIdentityId = imagePullIdentityAnnotation.Identity.Id.AsProvisioningParameter(infrastructure);
imagePullIdentityClientId = imagePullIdentityAnnotation.Identity.ClientId.AsProvisioningParameter(infrastructure);
}
else
{
if (sandboxResource.IsExisting())
{
throw CreateExistingSandboxGroupMissingAcrPullIdentityException(sandboxResource);
}
newImagePullIdentity = new UserAssignedIdentity(
Infrastructure.NormalizeBicepIdentifier($"{sandboxResource.Name}_mi"));
infrastructure.Add(newImagePullIdentity);
imagePullIdentityId = newImagePullIdentity.Id.ToBicepExpression();
imagePullIdentityClientId = newImagePullIdentity.ClientId.ToBicepExpression();
}View on GitHub (pinned to 25830f84bd)