{"record":{"id":"f9e48176e80c3e1d","repo":"microsoft/aspire","slug":"cancellationmessage-auxiliarybackchannelrpctarget","errorCode":null,"errorMessage":"{cancellationMessage}","messagePattern":"\\{cancellationMessage\\}","errorType":"exception","errorClass":"OperationCanceledException","httpStatus":null,"severity":"warning","filePath":"src/Aspire.Hosting/Backchannel/AuxiliaryBackchannelRpcTarget.cs","lineNumber":767,"sourceCode":"        ResourceNotificationService notificationService,\n        WaitResourceTarget target,\n        Func<ResourceEvent, bool> predicate,\n        string cancellationMessage,\n        CancellationToken cancellationToken)\n    {\n        try\n        {\n            await foreach (var resourceEvent in notificationService.WatchAsync(cancellationToken).ConfigureAwait(false))\n            {\n                if (target.Matches(resourceEvent) && predicate(resourceEvent))\n                {\n                    return resourceEvent;\n                }\n            }\n        }\n        catch (OperationCanceledException ex)\n        {\n            throw new OperationCanceledException(cancellationMessage, ex, ex.CancellationToken);\n        }\n\n        throw new OperationCanceledException(cancellationMessage);\n    }\n\n    private WaitTargetResolutionResult ResolveWaitTarget(ResourceNotificationService notificationService, string requestedResourceName)\n    {\n        var appModel = serviceProvider.GetRequiredService<DistributedApplicationModel>();\n        if (notificationService.TryGetCurrentState(requestedResourceName, out var resourceEvent))\n        {\n            return WaitTargetResolutionResult.Success(new WaitResourceTarget(\n                ResolveDisplayName(appModel, requestedResourceName, resourceEvent.ResourceId),\n                resourceEvent.ResourceId,\n                null));\n        }\n\n        // During startup the resource may not have published its first snapshot yet, so fall back to\n        // the app model to resolve the requested logical name or resolved resource id.","sourceCodeStart":749,"sourceCodeEnd":785,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting/Backchannel/AuxiliaryBackchannelRpcTarget.cs#L749-L785","documentation":"WaitForResourceEventAsync wraps OperationCanceledException from watching resource notifications and rethrows it with a descriptive cancellationMessage explaining which wait was cancelled (e.g. 'failed to become healthy before the operation was cancelled'). This is the inner-exception variant, preserving the original exception and its token.","triggerScenarios":"WaitForResourceAsync / WaitForHealthyAsync waits cancelled via the caller's CancellationToken or the linked timeout CTS while streaming ResourceNotificationService.WatchAsync — the wait never observed a matching resource event before cancellation.","commonSituations":"Caller-side cancellation (Ctrl+C, RPC client disconnect); the per-request timeout firing; resource taking longer than the wait window to publish a matching event.","solutions":["Increase request.TimeoutSeconds if the resource legitimately needs more time.","Check why the resource never reached the expected state (dashboard logs/state).","Inspect ex.CancellationToken / inner exception to determine whether the caller or the timeout cancelled.","Retry the wait once startup contention (slow image pull, cold start) has passed."],"exampleFix":"// before\nvar resp = await rpc.WaitForResourceAsync(new WaitForResourceRequest { ResourceName = \"api\", Status = \"healthy\", TimeoutSeconds = 10 });\n// after\nvar resp = await rpc.WaitForResourceAsync(new WaitForResourceRequest { ResourceName = \"api\", Status = \"healthy\", TimeoutSeconds = 120 });","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await rpc.WaitForResourceAsync(request); }\ncatch (OperationCanceledException ex) when (timeoutCts.IsCancellationRequested) { logger.LogWarning(ex, \"Wait cancelled by timeout; increase TimeoutSeconds or fix slow startup.\"); }","preventionTips":["Set generous TimeoutSeconds for slow-starting resources (image pulls, cold starts).","Distinguish caller cancellation from timeout via ex.CancellationToken.","Ensure the resource actually reaches the awaited state; check dashboard state."],"tags":["cancellation","timeout","wait"],"backgroundTag":"request-timeout","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"}