microsoft/aspire · error · InvalidOperationException

Azure sandbox group ' ' returned an invalid resource ID ' '.

Error message

Azure sandbox group '{sandboxGroup.Name}' returned an invalid resource ID '{resourceId}'.

What it means

Thrown when the 'id' output of an Azure sandbox group parses to an Azure.Core.ResourceIdentifier whose SubscriptionId, ResourceGroupName, or Name component is empty. The library needs those three components to build an AzureDevComputeResourceScope and rejects any malformed resource ID.

Solutions

  1. Verify the sandbox group's 'id' output is a full ARM resource ID: /subscriptions/{sub}/resourceGroups/{rg}/providers/{ns}/{type}/{name}.
  2. Regenerate the deployment state by re-running provisioning so a well-formed ID is emitted.
  3. If using a custom Bicep template, output the resource's `.id` property directly rather than constructing it manually.
  4. Check that resourceId.Name (not the collection-level ID) is being emitted by the template.

Example fix

// before
output id string = '/subscriptions/${sub}/sandboxGroups/${name}'
// after
output id string = sandboxGroup.id
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidArmId(string id) =>
    id.StartsWith("/subscriptions/") && id.Split('/').Length >= 9;

Type guard

static bool TryParseScope(string id, out (string Sub, string Rg, string Name) scope)
{
    var rid = new Azure.Core.ResourceIdentifier(id);
    scope = (rid.SubscriptionId ?? "", rid.ResourceGroupName ?? "", rid.Name ?? "");
    return scope.Sub != "" && scope.Rg != "" && scope.Name != "";
}

Prevention

When it happens

Trigger: CreateDataPlaneScope building `new ResourceIdentifier(GetRequiredOutput(sandboxGroup, "id"))` where the id string is not a fully-qualified ARM resource ID (missing subscription, resource group, or name segments).

Common situations: A hand-modified or mocked deployment state containing a partial ID like '/subscriptions/.../sandboxGroups' without a name; a custom Bicep template outputting an incomplete ID; typo'd ARM ID format.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Azure.Sandboxes/AzureSandboxContainerDeployment.cs:2332

    {
        if (!resource.Outputs.TryGetValue(name, out var value) || value is null || string.IsNullOrWhiteSpace(value.ToString()))
        {
            throw new InvalidOperationException($"Azure resource '{resource.Name}' is missing required output '{name}'. Ensure Azure infrastructure provisioning completed successfully.");
        }

        return value.ToString()!;
    }

    internal static AzureDevComputeResourceScope CreateDataPlaneScope(AzureSandboxGroupResource sandboxGroup)
    {
        ArgumentNullException.ThrowIfNull(sandboxGroup);

        var resourceId = new global::Azure.Core.ResourceIdentifier(GetRequiredOutput(sandboxGroup, "id"));
        if (string.IsNullOrWhiteSpace(resourceId.SubscriptionId) ||
            string.IsNullOrWhiteSpace(resourceId.ResourceGroupName) ||
            string.IsNullOrWhiteSpace(resourceId.Name))
        {
            throw new InvalidOperationException(
                $"Azure sandbox group '{sandboxGroup.Name}' returned an invalid resource ID '{resourceId}'.");
        }

        return new AzureDevComputeResourceScope(
            resourceId.SubscriptionId,
            resourceId.ResourceGroupName,
            resourceId.Name,
            GetRequiredOutput(sandboxGroup, "location"));
    }

    private static string CreateSandboxResourceName(string resourceName, string deployId)
    {
        var normalized = new string(resourceName.ToLowerInvariant().Select(static c => char.IsLetterOrDigit(c) ? c : '-').ToArray()).Trim('-');
        if (string.IsNullOrWhiteSpace(normalized))
        {
            normalized = "app";
        }

View on GitHub (pinned to 25830f84bd)