Skip to content

Conversation

@mag123c
Copy link
Contributor

@mag123c mag123c commented Oct 21, 2025

PR Checklist

Please check if your PR fulfills the following requirements:

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Other... Please describe:

What is the current behavior?

When a transient provider depends on another transient provider, each parent consumer should receive its own dedicated instance of the nested transient provider. However, in request/durable scoped contexts, nested transient providers are incorrectly shared across different parents, causing context pollution.

Issue Number: #15689

What is the new behavior?

Each parent now receives its own isolated instance of nested transient providers. The fix adds a getEffectiveInquirer() helper method that uses parentInquirer instead of inquirer when resolving transient-to-transient dependency chains in non-static contexts (REQUEST/DURABLE scopes).

Key changes:

  • Added getEffectiveInquirer() helper method in injector.ts
  • Applied to 4 injection points: constructor params, properties, metadata loading, scoped component resolution
  • Only affects TRANSIENT→TRANSIENT chains in REQUEST/DURABLE contexts
  • Preserves existing behavior for DEFAULT scope

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Similar but distinct from: #15553 / #15571: Lifecycle hook phantom instance bug (different root cause)

@coveralls
Copy link

coveralls commented Oct 21, 2025

Pull Request Test Coverage Report for Build f21074a3-8fcf-4ec1-a93c-75675d264f01

Details

  • 7 of 7 (100.0%) changed or added relevant lines in 1 file are covered.
  • 52 unchanged lines in 5 files lost coverage.
  • Overall coverage decreased (-0.2%) to 88.726%

Files with Coverage Reduction New Missed Lines %
packages/websockets/gateway-metadata-explorer.ts 1 95.24%
packages/common/module-utils/configurable-module.builder.ts 6 90.16%
packages/microservices/client/client-rmq.ts 7 65.84%
packages/websockets/web-sockets-controller.ts 9 87.67%
packages/microservices/server/server-rmq.ts 29 68.9%
Totals Coverage Status
Change from base Build daf86254-cf7e-4ef4-bff5-de9bcb9f9199: -0.2%
Covered Lines: 7280
Relevant Lines: 8205

💛 - Coveralls

@mag123c mag123c force-pushed the fix/transient-nested-dependency-isolation branch from 529943f to 4ffe045 Compare October 21, 2025 12:51
@kamilmysliwiec
Copy link
Member

Would you like to add an integration test for this, too?

@KamalAman
Copy link

KamalAman commented Oct 22, 2025

Oooh man, i think i've been fighting with this bug for 2 days now....

My symptoms are tenant databases are getting mixed up (in a sandbox env), and they are all resolving as the same latest database initialized for our durable database providers.


Update: My bad, i've isolated my bug to updating "@nestjs-cls/transactional" "2.5.1" -> "2.6".

Papooch/nestjs-cls#404

@kamilmysliwiec
Copy link
Member

LGTM

@kamilmysliwiec kamilmysliwiec merged commit 334012e into nestjs:master Oct 27, 2025
4 checks passed
@NicChoi
Copy link

NicChoi commented Dec 19, 2025

@kamilmysliwiec Hello, the bug seems not to be fixed, please see my demo https://github.com/NicChoi/nestjs-transient

The AppController uses the MyService (TRANSIENT), and the MyService uses the MyLogger (TRANSIENT)
The constructor and the onModuleInit is not be called in the MyLogger
Finally, call the this.logger.error in the MyService
the "this.logger" in the MyLogger is undefined

@mag123c
Copy link
Contributor Author

mag123c commented Dec 19, 2025

@NicChoi

Thanks for reporting this. However, after analyzing your demo repository, this appears to be a different issue from what #15689 addressed.

#15689 (this PR): resolved

  • Scope chain: REQUEST → TRANSIENT → TRANSIENT
  • Symptom: Nested transient instances were shared incorrectly
  • Fix applies when contextId !== STATIC_CONTEXT

Your case:

  • Scope chain: DEFAULT (Singleton) → TRANSIENT → TRANSIENT
  • Symptom: Nested transient instance is undefined
  • Uses STATIC_CONTEXT, so this fix doesn't apply

The getEffectiveInquirer method specifically targets REQUEST/DURABLE scope contexts. Your scenario starts from a default-scoped controller, which is a separate issue.

Could you please open a new issue with your reproduction repository? This will help the maintainers track and address it properly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants