{"record":{"id":"d184264e0f6c7a21","repo":"microsoft/aspire","slug":"stopped-waiting-for-resource-resourcename-to-become-healthy-d18426","errorCode":null,"errorMessage":"Stopped waiting for resource '{resourceName}' to become healthy because it failed to start.","messagePattern":"Stopped waiting for resource '(.+?)' to become healthy because it failed to start\\.","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/ApplicationModel/ResourceNotificationService.cs","lineNumber":266,"sourceCode":"            var appModel = _serviceProvider.GetService<DistributedApplicationModel>();\n            if (appModel is not null && !appModel.Resources.Any(r => string.Equals(r.Name, resourceName, StringComparisons.ResourceName)))\n            {\n                _logger.LogError(\"Stopped waiting for resource '{ResourceName}' to become healthy because it does not exist in the application model.\", resourceName);\n                throw new DistributedApplicationException($\"Stopped waiting for resource '{resourceName}' to become healthy because it does not exist in the application model.\");\n            }\n        }\n\n        var resourceEvent = await WaitForResourceCoreAsync(\n            resourceName,\n            re => ShouldYieldHealthyWait(waitBehavior, re.Snapshot),\n            $\"Resource '{resourceName}' failed to become healthy before the operation was cancelled.\",\n            waitCondition: \"healthy\",\n            cancellationToken: cancellationToken).ConfigureAwait(false);\n\n        if (resourceEvent.Snapshot.HealthStatus != HealthStatus.Healthy)\n        {\n            _logger.LogError(\"Stopped waiting for resource '{ResourceName}' to become healthy because it failed to start.\", resourceName);\n            throw new DistributedApplicationException($\"Stopped waiting for resource '{resourceName}' to become healthy because it failed to start.\");\n        }\n\n        // Now wait for the resource ready event to be executed (matching behavior of WaitUntilHealthyAsync).\n        _logger.LogDebug(\"Waiting for resource ready to execute for '{ResourceName}'.\", resourceName);\n        resourceEvent = await WaitForResourceCoreAsync(\n            resourceName,\n            re => re.ResourceId == resourceEvent.ResourceId && re.Snapshot.ResourceReadyEvent is not null,\n            $\"Resource '{resourceName}' failed to execute the resource ready event before the operation was cancelled.\",\n            waitCondition: \"resource_ready\",\n            cancellationToken: cancellationToken).ConfigureAwait(false);\n\n        // Observe the result of the resource ready event task\n        await resourceEvent.Snapshot.ResourceReadyEvent!.EventTask.WaitAsync(cancellationToken).ConfigureAwait(false);\n\n        _logger.LogDebug(\"Finished waiting for resource '{ResourceName}'.\", resourceName);\n\n        return resourceEvent;\n    }","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/ApplicationModel/ResourceNotificationService.cs#L248-L284","documentation":"Thrown by WaitForResourceHealthyAsync when a resource being waited on reaches the end of its start attempt in a state other than Healthy (e.g. FailedToStart, Exited, Finished). The library stops waiting instead of blocking indefinitely and surfaces a DistributedApplicationException so the app model fails fast with a clear reason.","triggerScenarios":"Calling builder.CreateResourceBuilder(resource).WaitForResourceHealthy(name) (or the public WaitForResourceHealthyAsync) while the target resource transitions to FailedToStart, Exited, Finished, or RuntimeUnhealthy instead of Healthy.","commonSituations":"Container image cannot be pulled or crashes at startup; connection strings or env vars invalid so the child app dies during boot; dependency database not ready so the resource's own startup health checks fail; port conflicts.","solutions":["Inspect the resource's logs in the Aspire dashboard to find why it failed to start (missing env var, bad image, crash).","Fix the resource configuration (image tag, connection string, bindings) so it can become healthy.","If the resource legitimately exits after work (batch job), use WaitForCompletion with an expected exit code instead of WaitForResourceHealthy.","Ensure required dependencies are ordered with WithReference so they start before the failing resource.","Wrap the AppHost startup/wait in try-catch on DistributedApplicationException when failure is an expected runtime condition."],"exampleFix":"// before\nbuilder.AddProject<Projects.Api>(\"api\")\n    .WaitForResourceHealthy(\"db\");\n\n// after (db is a one-shot migrator job, so wait for successful completion instead)\nbuilder.AddProject<Projects.Api>(\"api\")\n    .WaitForCompletion(\"db\", exitCode: 0);","handlingStrategy":"try-catch","validationCode":"// Verify the dependency exposes health checks before waiting on 'healthy'\nif (resourceBuilder.Resource is IResourceWithHealthCheck)\n{\n    builder.WaitForResourceHealthy(resourceBuilder.Resource.Name);\n}","typeGuard":null,"tryCatchPattern":"try\n{\n    await app.StartAsync();\n}\ncatch (DistributedApplicationException ex) when (ex.Message.Contains(\"failed to start\"))\n{\n    logger.LogError(ex, \"Dependency failed to start; check dashboard logs.\");\n}","preventionTips":["Add health checks/health endpoints to resources before waiting on 'healthy'.","Fix container images and env config so resources can start reliably.","Use WaitForCompletion for one-shot jobs instead of health waits.","Check the dashboard resource logs first when diagnosing."],"tags":["aspire","orchestration","resource-health","startup"],"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"}