microsoft/aspire · error · InvalidOperationException

ADC request ' ' failed with HTTP ( ).

Error message

ADC request '{method} {path}' failed with HTTP {(int)response.StatusCode} ({response.ReasonPhrase}). {message}{permissionHint}

What it means

EnsureSuccessAsync is the ADC client's non-success HTTP handler: for any non-success status it reads an error message from the response body and throws InvalidOperationException including the method, path, numeric status code, reason phrase, body message, and — for 403 — a hint to verify the caller has the Container Apps SandboxGroup Data Owner role on the sandbox group. It is raised by every SendAsync/SendCreateAsync call that gets an error status.

Solutions

  1. If status is 403, assign the Container Apps SandboxGroup Data Owner role to the calling principal on the sandbox group and wait a few minutes for propagation, then retry.
  2. Read the embedded message from the exception to identify the specific status (401 vs 404 vs 429 vs 5xx) and address accordingly.
  3. Verify your Azure credentials (az login, managed identity, or service principal) target the correct tenant and subscription.
  4. Retry transient failures (429/5xx) with backoff; check Azure status for ADC outages.
  5. Confirm the sandbox group name/path used in the request is correct.

Example fix

// before: no RBAC role on principal
// HTTP 403 thrown by EnsureSuccessAsync
// after (Azure CLI)
az role assignment create --assignee <principalId> --role "Container Apps SandboxGroup Data Owner" --scope <sandboxGroupId>
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: verify the principal's RBAC role before calling ADC
az role assignment list --assignee <principalId> --scope <sandboxGroupId>
// Expect "Container Apps SandboxGroup Data Owner" in results

Try / catch

try
{
    await client.SendAsync(request, ct);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("HTTP 403"))
{
    // grant SandboxGroup Data Owner role, wait for propagation, retry with backoff
}
catch (InvalidOperationException ex) when (ex.Message.Contains("HTTP 429") || ex.Message.Contains("HTTP 5"))
{
    // transient: retry with exponential backoff
}

Prevention

When it happens

Trigger: Any ADC HTTP request (via SendAsync or SendCreateAsync) that returns 4xx/5xx; most specifically an HTTP 403 Forbidden when the calling principal lacks the Container Apps SandboxGroup Data Owner role assignment.

Common situations: RBAC role assignment not yet propagated right after granting access (the hint notes propagation delay); wrong tenant/subscription; expired or insufficient credentials; sandbox group not found (404); service outage (5xx).

Understand the failure class

Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Azure.Sandboxes/Internal/Adc/AzureDevComputeClient.cs:465

            return _accessToken.Token;
        }

        _accessToken = await credential.GetTokenAsync(new TokenRequestContext(s_authorizationScopes), cancellationToken).ConfigureAwait(false);
        return _accessToken.Token;
    }

    private static async Task EnsureSuccessAsync(HttpResponseMessage response, HttpMethod method, string path, CancellationToken cancellationToken)
    {
        if (response.IsSuccessStatusCode)
        {
            return;
        }

        var message = await GetErrorMessageAsync(response, cancellationToken).ConfigureAwait(false);
        var permissionHint = response.StatusCode == HttpStatusCode.Forbidden
            ? " Verify that the calling principal has the Container Apps SandboxGroup Data Owner role on the sandbox group; newly-created role assignments can take a short time to propagate."
            : string.Empty;
        throw new InvalidOperationException($"ADC request '{method} {path}' failed with HTTP {(int)response.StatusCode} ({response.ReasonPhrase}). {message}{permissionHint}");
    }

    private static Task<string> GetErrorMessageAsync(HttpResponseMessage response, CancellationToken cancellationToken)
    {
        cancellationToken.ThrowIfCancellationRequested();
        if (response.Content.Headers.ContentLength == 0)
        {
            return Task.FromResult(string.Empty);
        }

        return Task.FromResult("The service returned an error response whose details were redacted.");
    }

    private static string GetSandboxGroupPath(AzureDevComputeResourceScope scope)
    {
        return $"subscriptions/{Escape(scope.SubscriptionId)}/resourceGroups/{Escape(scope.ResourceGroupName)}/sandboxGroups/{Escape(scope.SandboxGroupName)}";
    }

View on GitHub (pinned to 25830f84bd)