{"record":{"id":"e374a6ca2f5aadb3","repo":"microsoft/aspire","slug":"app-service-plan-id-appserviceplanid-does-not-contain-a-e374a6","errorCode":null,"errorMessage":"App Service plan id '{appServicePlanId}' does not contain a resource group name.","messagePattern":"App Service plan id '(.+?)' does not contain a resource group name\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Azure.AppService/AppSvcUrls.cs","lineNumber":35,"sourceCode":"    {\n        var planIdValue = await computerEnv.PlanIdOutputReference.GetValueAsync(cancellationToken).ConfigureAwait(false)\n            ?? throw new InvalidOperationException($\"Missing app service plan id output for '{computerEnv.Name}'.\");\n        var (subscriptionId, resourceGroupName) = GetSubscriptionAndResourceGroup(planIdValue);\n        var resourceId = $\"{AzurePortalUrls.GetResourceGroupResourceId(subscriptionId, resourceGroupName)}{SiteResourceType}{siteName}\";\n\n        if (!string.IsNullOrWhiteSpace(deploymentSlot))\n        {\n            resourceId += $\"{SlotPathPrefix}{deploymentSlot}\";\n        }\n\n        return AzurePortalUrls.GetResourceLink(resourceId);\n    }\n\n    private static (string SubscriptionId, string ResourceGroupName) GetSubscriptionAndResourceGroup(string appServicePlanId)\n    {\n        var planId = new ResourceIdentifier(appServicePlanId);\n        var subscriptionId = planId.SubscriptionId ?? throw new InvalidOperationException($\"App Service plan id '{appServicePlanId}' does not contain a subscription id.\");\n        var resourceGroupName = planId.ResourceGroupName ?? throw new InvalidOperationException($\"App Service plan id '{appServicePlanId}' does not contain a resource group name.\");\n\n        return (subscriptionId, resourceGroupName);\n    }\n}\n","sourceCodeStart":17,"sourceCodeEnd":40,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.AppService/AppSvcUrls.cs#L17-L40","documentation":"When Aspire builds an Azure Portal link for an App Service, it parses the plan's ARM resource ID to extract the subscription and resource group. Azure Resource Manager resource IDs always contain both segments; this error means the ID string parsed successfully but had no resource group segment, so a valid portal URL cannot be constructed.","triggerScenarios":"GetPortalLinkAsync -> GetSubscriptionAndResourceGroup was handed an appServicePlanId string that is a ResourceIdentifier but lacks the /resourceGroups/{name}/ segment — e.g. a malformed or partially constructed plan ID stored in the environment model, or an ID from a mock/test/stub provisioning path.","commonSituations":"Custom or stubbed Azure provisioning that sets the App Service plan ID to a simplified identifier; hand-edited Bicep outputs; test fakes that supply subscription-only IDs; corruption when an ID is templated or interpolated incorrectly.","solutions":["Inspect the actual plan ID value logged with the exception and ensure it is a full ARM ID like /subscriptions/{sub}/resourceGroups/{rg}/providers/Microsoft.Web/serverfarms/{plan}.","If you supply the plan ID yourself (e.g. via existing resource/ByOutput references), point it at a real deployed serverfarm output, not a hand-built string.","Check that your Azure provisioning context is real (not a mock) so the plan ID comes from an actual deployment output.","Upgrade Aspire packages to the latest patch in case the plan ID wiring bug was fixed."],"exampleFix":"// before\nvar planId = \"/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Web/serverfarms/asp\";\n// after\nvar planId = \"/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/my-rg/providers/Microsoft.Web/serverfarms/asp\";","handlingStrategy":"validation","validationCode":"if (new Azure.ResourceManager.Resources.ResourceIdentifier(planId) is { } id && id.ResourceGroupName is null) throw new ArgumentException(\"Plan id missing resource group\", nameof(planId));","typeGuard":"static bool HasResourceGroup(string armId) => armId.Contains(\"/resourceGroups/\", StringComparison.OrdinalIgnoreCase);","tryCatchPattern":"try { var (sub, rg) = GetSubscriptionAndResourceGroup(planId); } catch (InvalidOperationException ex) { logger.LogError(ex, \"Malformed App Service plan id: {PlanId}\", planId); }","preventionTips":["Always source plan IDs from real ARM deployment outputs, never hand-built strings.","Assert ARM IDs contain /resourceGroups/ in tests with fake provisioning.","Log the raw plan ID whenever portal-link construction fails."],"tags":["azure","appservice","arm-resource-id"],"backgroundTag":"invalid-identifier-format","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}