{"record":{"id":"07540decb1c4ac4a","repo":"microsoft/aspire","slug":"resource-update-buffering-was-not-enabled-for-this-watcher","errorCode":null,"errorMessage":"Resource update buffering was not enabled for this watcher.","messagePattern":"Resource update buffering was not enabled for this watcher\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Cli/Backchannel/ResourceSnapshotWatcher.cs","lineNumber":214,"sourceCode":"                    retainedVersion);\n                continue;\n            }\n\n            _updateSignal?.Writer.TryWrite(true);\n        }\n    }\n\n    /// <summary>\n    /// Streams updates from the same subscription that maintains the current resource collection.\n    /// Callers should first capture the initial state with <see cref=\"CaptureAllResources\"/>.\n    /// The update stream can be enumerated only once over the lifetime of the watcher.\n    /// </summary>\n    public async IAsyncEnumerable<ResourceSnapshotUpdateBatch> WatchResourceSnapshotBatchesAsync(\n        long afterSequence,\n        [EnumeratorCancellation] CancellationToken cancellationToken = default)\n    {\n        EnsureInitialLoadComplete();\n        var updateSignal = _updateSignal ?? throw new InvalidOperationException(\"Resource update buffering was not enabled for this watcher.\");\n        if (Interlocked.Exchange(ref _updateConsumerClaimed, 1) != 0)\n        {\n            throw new InvalidOperationException(\"Resource snapshot updates support only one consumer for the lifetime of this watcher.\");\n        }\n\n        await foreach (var _ in updateSignal.Reader.ReadAllAsync(cancellationToken).ConfigureAwait(false))\n        {\n            ResourceSnapshotUpdate[] updates;\n            bool isResync;\n            lock (_resourcesLock)\n            {\n                if (_resyncPending)\n                {\n                    updates = _resources.Values\n                        .Select(snapshot => new ResourceSnapshotUpdate(_updateSequence, snapshot))\n                        .ToArray();\n                    _resyncPending = false;\n                    isResync = true;","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Cli/Backchannel/ResourceSnapshotWatcher.cs#L196-L232","documentation":"ResourceSnapshotWatcher can be constructed without update buffering; WatchResourceSnapshotBatchesAsync requires the internal buffered update channel (_updateSignal) to exist. If buffering was never enabled, the watcher throws InvalidOperationException because it has no way to stream snapshot updates. This is a programming/configuration error, not a runtime fault.","triggerScenarios":"Calling WatchResourceSnapshotBatchesAsync on a ResourceSnapshotWatcher instance that was created with update buffering disabled (no capacity/options enabling the update signal buffer).","commonSituations":"Reusing a watcher built for one-shot polling (CaptureAllResources/GetResources) and then trying to stream updates from it; constructing the watcher with default options that don't enable buffering.","solutions":["Construct ResourceSnapshotWatcher with update buffering enabled (the option that allocates the update signal channel).","Create a dedicated watcher instance for streaming updates instead of reusing a polling-only watcher.","Fall back to polling GetResources/CaptureAllResources if streaming is not required."],"exampleFix":"// before\nvar watcher = new ResourceSnapshotWatcher(connection); // buffering not enabled\nawait watcher.WatchResourceSnapshotBatchesAsync(0, ct);\n// after\nvar watcher = new ResourceSnapshotWatcher(connection, new ResourceSnapshotWatcherOptions { EnableUpdateBuffering = true });\nawait watcher.WatchResourceSnapshotBatchesAsync(0, ct);","handlingStrategy":"validation","validationCode":"// before streaming, ensure buffering was enabled at construction\nif (!watcherOptions.EnableUpdateBuffering) throw new NotSupportedException(\"Create the watcher with update buffering enabled to stream updates.\");","typeGuard":null,"tryCatchPattern":"try { await foreach (var b in watcher.WatchResourceSnapshotBatchesAsync(0, ct)) { } }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"buffering\")) { /* fall back to polling GetResources */ }","preventionTips":["Enable update buffering when constructing a watcher you intend to stream from","Keep polling and streaming watchers as separate instances","Document per-instance capabilities in your wrapper around ResourceSnapshotWatcher"],"tags":["cli","watcher","invalid-state","streaming"],"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"}