{"record":{"id":"3f982a51a9a68220","repo":"microsoft/aspire","slug":"azure-sandbox-resources-resource-targetresource-name-and","errorCode":null,"errorMessage":"Azure sandbox resources '{resource.TargetResource.Name}' and '{producer.TargetResource.Name}' have a circular deployment dependency.","messagePattern":"Azure sandbox resources '(.+?)' and '(.+?)' have a circular deployment dependency\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.Azure.Sandboxes/AzureSandboxContainerDeployment.cs","lineNumber":180,"sourceCode":"            if (dependency.GetDeploymentTargetAnnotation()?.DeploymentTarget is not AzureSandboxContainerResource producer)\n            {\n                continue;\n            }\n\n            if (!ReferenceEquals(producer.Parent, resource.Parent))\n            {\n                throw new NotSupportedException(\n                    $\"Azure sandbox resource '{resource.TargetResource.Name}' in sandbox group '{resource.Parent.Name}' references resource '{dependency.Name}' in sandbox group '{producer.Parent.Name}', but cross-group sandbox references are not supported. Deploy both resources to the same sandbox group.\");\n            }\n\n            var producerSteps = context.GetSteps(producer, WellKnownPipelineTags.DeployCompute);\n            foreach (var consumerStep in deploySteps)\n            {\n                foreach (var producerStep in producerSteps)\n                {\n                    if (WouldCreateDependencyCycle(context.Steps, consumerStep, producerStep))\n                    {\n                        throw new InvalidOperationException(\n                            $\"Azure sandbox resources '{resource.TargetResource.Name}' and '{producer.TargetResource.Name}' have a circular deployment dependency.\");\n                    }\n\n                    consumerStep.DependsOn(producerStep);\n                }\n            }\n        }\n    }\n\n    private static IEnumerable<PipelineStep> GetAzureEnvironmentDestroySteps(PipelineConfigurationContext context)\n    {\n        foreach (var environment in context.Model.Resources.OfType<AzureEnvironmentResource>())\n        {\n            var expectedName = $\"destroy-azure-{environment.Name}\";\n            foreach (var step in context.GetSteps(environment).Where(step => string.Equals(step.Name, expectedName, StringComparison.Ordinal)))\n            {\n                yield return step;\n            }","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.Azure.Sandboxes/AzureSandboxContainerDeployment.cs#L162-L198","documentation":"When wiring deploy-order dependencies between sandbox resources, adding a consumer-step dependency on a producer-step would create a cycle in the pipeline step graph. Aspire detects this with WouldCreateDependencyCycle and throws InvalidOperationException instead of producing a deadlocked deployment order.","triggerScenarios":"Two sandbox resources reference each other's outputs (A references B and B references A), or an indirect cycle exists across several WithReference calls, so consumerStep.DependsOn(producerStep) would close a loop.","commonSituations":"Mutually dependent services (each calling the other and both modeled with WithReference), or a refactoring that accidentally reversed a dependency direction.","solutions":["Break the cycle: remove one WithReference so the dependency graph is acyclic.","Extract the shared value (e.g. an endpoint or connection string) into an explicitly configured parameter instead of mutual resource references.","Restructure the app so the dependency is one-directional (producer consumed by consumer only)."],"exampleFix":"// before\napi.WithReference(worker); worker.WithReference(api); // cycle\n// after\napi.WithReference(worker); // worker no longer references api; pass api's URL as config","handlingStrategy":"validation","validationCode":"// before deploy: detect reference cycles in the sandbox resource graph\nbool HasCycle(Dictionary<string, string[]> edges) =>\n    // DFS with visit states; report any node reachable from itself","typeGuard":null,"tryCatchPattern":"try { await deployment.ConfigureDeployOrderingAsync(...); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"circular deployment dependency\")) { /* break the WithReference cycle flagged in the message */ }","preventionTips":["Keep resource dependencies one-directional; never A.WithReference(B) plus B.WithReference(A).","Extract shared endpoints into parameters when two services need each other.","Sketch the dependency DAG before adding references."],"tags":["azure","sandboxes","dependency-cycle"],"backgroundTag":"invalid-state-transition","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"}