{"record":{"id":"d4e4d5a612518e63","repo":"microsoft/aspire","slug":"unexpected-wait-behavior-waitbehavior","errorCode":null,"errorMessage":"Unexpected wait behavior: {waitBehavior}","messagePattern":"Unexpected wait behavior: (.+?)","errorType":"exception","errorClass":"DistributedApplicationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting/ApplicationModel/ResourceNotificationService.cs","lineNumber":295,"sourceCode":"\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    }\n\n    internal static bool ShouldYieldHealthyWait(WaitBehavior waitBehavior, CustomResourceSnapshot snapshot) =>\n        waitBehavior switch\n        {\n            WaitBehavior.WaitOnResourceUnavailable => snapshot.HealthStatus == HealthStatus.Healthy,\n            WaitBehavior.StopOnResourceUnavailable => snapshot.HealthStatus == HealthStatus.Healthy ||\n                                                  snapshot.State?.Text == KnownResourceStates.Finished ||\n                                                  snapshot.State?.Text == KnownResourceStates.Exited ||\n                                                  snapshot.State?.Text == KnownResourceStates.FailedToStart ||\n                                                  snapshot.State?.Text == KnownResourceStates.RuntimeUnhealthy,\n            _ => throw new DistributedApplicationException($\"Unexpected wait behavior: {waitBehavior}\")\n        };\n\n    private async Task WaitUntilCompletionAsync(IResource resource, IResource dependency, int exitCode, CancellationToken cancellationToken, Func<string, Task>? onDependencyReady = null)\n    {\n        using var activity = ProfilingTelemetry.StartResourceWaitForDependency(Configuration, resource, dependency, WaitType.WaitForCompletion, waitBehavior: null);\n        activity.SetResourceWaitExpectedExitCode(exitCode);\n\n        var names = dependency.GetResolvedResourceNames();\n        var tasks = new Task[names.Length];\n\n        var resourceLogger = _resourceLoggerService.GetLogger(resource);\n        resourceLogger.LogInformation(\"Waiting for resource '{ResourceName}' to complete.\", dependency.Name);\n\n        for (var i = 0; i < names.Length; i++)\n        {\n            var displayName = names.Length > 1 ? names[i] : dependency.Name;\n            tasks[i] = Core(displayName, names[i]);\n        }","sourceCodeStart":277,"sourceCodeEnd":313,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/ApplicationModel/ResourceNotificationService.cs#L277-L313","documentation":"Internal invariant guard in ShouldYieldHealthyWait: the waitBehavior value did not match WaitOnResourceUnavailable or StopOnResourceUnavailable, so the switch fell to the default arm. WaitBehavior is an enum and this indicates an unknown/invalid enum value was supplied.","triggerScenarios":"Passing an out-of-range or undefined WaitBehavior value (e.g. a cast of an arbitrary int or a default value that is not a defined member) into a wait annotation / WaitFor API that evaluates ShouldYieldHealthyWait.","commonSituations":"Custom resource extensions or copy-pasted wait annotation code passing an uninitialized enum (default 0 if not a defined member); library version drift where an older caller passes a WaitBehavior value removed or renamed in a newer Aspire version.","solutions":["Only pass explicitly defined members: WaitBehavior.WaitOnResourceUnavailable or WaitBehavior.StopOnResourceUnavailable.","Audit custom code or extensions that construct WaitAnnotation and remove int casts or default(WaitBehavior) usage.","Align package versions across all Aspire projects so the enum definition matches the hosting library."],"exampleFix":"// before\nvar annotation = new WaitAnnotation(dep, WaitType.WaitUntilHealthy) { WaitBehavior = (WaitBehavior)3 };\n\n// after\nvar annotation = new WaitAnnotation(dep, WaitType.WaitUntilHealthy) { WaitBehavior = WaitBehavior.StopOnResourceUnavailable };","handlingStrategy":"validation","validationCode":"bool IsValid(WaitBehavior b) => b is WaitBehavior.WaitOnResourceUnavailable or WaitBehavior.StopOnResourceUnavailable;\nif (!IsValid(annotation.WaitBehavior)) throw new ArgumentException($\"Unsupported WaitBehavior: {annotation.WaitBehavior}\");","typeGuard":"static bool IsDefinedWaitBehavior(WaitBehavior value) =>\n    Enum.IsDefined(typeof(WaitBehavior), value);","tryCatchPattern":"try\n{\n    // wait annotation processing\n}\ncatch (DistributedApplicationException ex) when (ex.Message.Contains(\"Unexpected wait behavior\"))\n{\n    logger.LogError(ex, \"Invalid WaitBehavior enum value supplied.\");\n}","preventionTips":["Never cast ints to WaitBehavior; use named enum members only.","Avoid default(WaitBehavior); always set the property explicitly.","Keep Aspire.Hosting package versions aligned across projects.","Add a unit test asserting only defined enum values are used in annotations."],"tags":["aspire","enum","wait-behavior","invariant"],"backgroundTag":"invalid-enum-value","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}