microsoft/aspire · error

The persisted scope is not a JSON object.

Error message

The persisted scope is not a JSON object.

What it means

Thrown while parsing the persisted 'Scope' value from the AKS deployment state: the stored value is not a JSON object (JsonNode.Parse returned a non-object or null). The scope must be a JSON object like {"resourceGroup":"shared-rg","subscription":"<guid>"} as written by BicepUtilities.SetScopeAsync.

Solutions

  1. Inspect the Scope value in the deployment state file and fix it to the JSON object shape {"resourceGroup":...,"subscription":...}
  2. Re-deploy the environment so BicepUtilities.SetScopeAsync rewrites the scope in the correct shape
  3. If a custom module writes Scope, ensure it stores a JSON-encoded object, not a raw string
  4. Delete stale state and redeploy from scratch

Example fix

// before (bad stored value)
// "Scope": "shared-rg/00000000-0000-0000-0000-000000000000"
// after (correct)
// "Scope": "{ \"resourceGroup\": \"shared-rg\", \"subscription\": \"00000000-0000-0000-0000-000000000000\" }"
Defensive patterns

Strategy: validation

Validate before calling

var scopeJson = state.Data["Scope"];
using var doc = JsonDocument.Parse(scopeJson);
if (doc.RootElement.ValueKind != JsonValueKind.Object)
    throw new InvalidOperationException("Scope must be a JSON object with resourceGroup/subscription.");

Prevention

When it happens

Trigger: GetAksCredentialsForDestroyAsync reads deploymentStateSection.Data["Scope"], calls JsonNode.Parse(...).AsObject(), and the parsed node is a string/number/array/null instead of an object.

Common situations: The Scope output in the deployment state was corrupted or replaced by a plain string; a custom template wrote the scope without JSON encoding; state was hand-edited or migrated from a different schema version.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


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

Appendix: source

Thrown at src/Aspire.Hosting.Azure.Kubernetes/AzureKubernetesEnvironmentResource.AksPipeline.cs:420

        // Scope is persisted as a JSON string using the same shape produced by
        // BicepUtilities.SetScopeAsync:
        //   { "resourceGroup": "shared-rg", "subscription": "00000000-..." }
        // A missing property means the resource did not pin that scope value, so only that value
        // falls back to global Azure deployment state. Older state without Scope uses the persisted
        // resource ID so a changed AppHost scope cannot redirect cleanup to another cluster or wait
        // on provisioning that is not part of the destroy graph.
        string subscriptionId;
        string? resourceGroupName;
        if (deploymentStateSection.Data["Scope"] is not null)
        {
            string? scopedSubscription;
            string? scopedResourceGroup;
            try
            {
                var scopeJson = deploymentStateSection.Data["Scope"]!.GetValue<string>();
                var scope = JsonNode.Parse(scopeJson)?.AsObject()
                    ?? throw new InvalidOperationException("The persisted scope is not a JSON object.");
                scopedSubscription = scope["subscription"]?.GetValue<string>();
                scopedResourceGroup = scope["resourceGroup"]?.GetValue<string>();
            }
            catch (Exception ex) when (ex is not OperationCanceledException)
            {
                throw new InvalidOperationException(
                    $"The Azure deployment state for AKS environment '{Name}' contains an invalid scope.",
                    ex);
            }

            (subscriptionId, resourceGroupName) = await ResolveDeploymentScopeAsync(
                scopedSubscription,
                scopedResourceGroup,
                context.Services,
                context.CancellationToken).ConfigureAwait(false);
        }
        else
        {

View on GitHub (pinned to 25830f84bd)