Repository navigation
fix(core): subscribe to handler observables from other rxjs copies - #18215
Merged
kamilmysliwiec merged 1 commit intoOct 21, 2026
Merged
Conversation
InterceptorsConsumer recognised an Observable returned by a route handler only with "instanceof Observable", against the copy of rxjs @nestjs/core loads. An Observable from another copy, such as one a client library brings along, was never subscribed to: the Observable object itself was emitted to the interceptors and sent as the response, while the same handler worked without interceptors. The result is now checked with isObservable(), as GuardsConsumer already does, so the values such an Observable emits are passed on.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
InterceptorsConsumer.transformDeferred()decides whether a handler's result is a stream withres instanceof Observable, which only matches the copy of rxjs that@nestjs/coreloads. When a handler returns an Observable created by another copy of rxjs (e.g. one bundled by a client library, or a duplicated rxjs in a monorepo), the check fails and the result is wrapped withPromise.resolve(res). The Observable is never subscribed: interceptors receive the Observable object itself innext.handle(), and it is sent as the response (serialized as{}).The same handler works without interceptors, because
RouterExecutionContext/RouterResponseControlleralready useisObservable(), so adding any interceptor (even a pass-through, or a globalClassSerializerInterceptor) changes the response.This is the same class of issue that fec478e fixed for guards in
GuardsConsumer.Issue Number: N/A
What is the new behavior?
transformDeferred()checks the result withisObservable(), asGuardsConsumeralready does, so Observables from other copies of rxjs are subscribed and the values they emit are passed through the interceptor chain. Added a regression test tointerceptors-consumer.spec.ts(fails before the change, passes after).Does this PR introduce a breaking change?
Other information
packages/core,packages/microservicesandpackages/websocketsunit tests pass except 4 tests (router-exception-filters,client-kafka,server-redis) that fail identically on currentmasterwithout this change.