ProxyProviderNotResolvedException thrown even after resolveProxyProviders(...) inside cls.run(...)
Summary
We occasionally get ProxyProviderNotResolvedException when accessing a proxy provider, despite resolving it right before usage inside clsService.run(...).
This happens rarely and non-deterministically in production workers (BullMQ). It looks like a race between proxy resolution and access, or a context boundary issue.
Error
ProxyProviderNotResolvedException: Cannot access the property "getHash" on the Proxy provider UserSettingDocument because is has not been resolved yet and has been registered with the "strict: true" option. Make sure to call "await cls.resolveProxyProviders()" before accessing the Proxy provider.
at Function.create (/app/node_modules/nestjs-cls/dist/src/lib/proxy-provider/proxy-provider.exceptions.js:69:16)
at checkAllowedPropertyAccess (/app/node_modules/nestjs-cls/dist/src/lib/proxy-provider/proxy-provider-manager.js:180:81)
at Object.get (/app/node_modules/nestjs-cls/dist/src/lib/proxy-provider/proxy-provider-manager.js:119:51)
at QuestPrizeGeneratorWorker.resolveProxyProviders (/apps/meta-server/src/@job/common/job-worker.ts:46:59)
at processTicksAndRejections (node:internal/process/task_queues:95:5)
at QuestPrizeGeneratorWorker.prepareContext (/apps/meta-server/src/@job/common/context-job.worker.ts:24:5)
at QuestPrizeGeneratorWorker.execute (/apps/meta-server/src/@job/common/context-job.worker.ts:36:5)
at /app/node_modules/bullmq/src/classes/worker.ts:910:26
at Worker.retryIfFailed (/app/node_modules/bullmq/src/classes/worker.ts:1174:16)
What we do
@Injectable()
export class ExampleService {
constructor(
private readonly clsService: ClsService,
@Inject(UserSettingDocument) private readonly settingDocument: UserSettingDocument, // proxied provider
) {}
public example() {
return this.clsService.run(async () => {
await this.clsService.resolveProxyProviders([UserSettingDocument]);
// Rarely throws ProxyProviderNotResolvedException here:
this.settingDocument.getHash();
return true;
});
}
}
Expected behavior
No exception is thrown after await clsService.resolveProxyProviders([...]) has completed within the same cls.run(...) scope.
Actual behavior
Very rarely (hard to reproduce locally), an exception is thrown saying the proxy has not been resolved yet. It happens in BullMQ worker jobs.
Environment
- nestjs-cls: 5.0.1
- NestJS: 10.3.5
- Node.js: 18.20.0
- Package manager: yarn 1.22.19
- Platform: BullMQ workers (separate process), Linux (Docker)
- BullMQ: 5.8.4
- strict mode:
strict: true for proxy provider registration
- cls setup:
ClsModule.forRoot({ global: true, middleware: { mount: true } })
- Repository type: monorepo (private)
Minimal reproduction (suggested outline)
I haven’t been able to produce a stable repro, but a flaky one could be:
- Start a BullMQ worker that wraps each job in
clsService.run(...).
- Register a proxy provider with
strict: true.
- Inside a job handler:
await cls.resolveProxyProviders([ProxyToken])
await new Promise(r => setImmediate(r)) (force a macro-task hop)
- Access a method on the proxied provider.
Sometimes this still throws in our environment.
If there’s an official recommended pattern, I’m happy to test it and provide a full repro repo.
Workarounds tried
- Moving
resolveProxyProviders earlier in the call chain — still happens.
- Ensuring access happens synchronously right after resolve (reduced frequency but didn’t eliminate).
Thanks a lot! Happy to provide more logs or build a repro if you can point me to the right pattern to ensure context consistency.
ProxyProviderNotResolvedException thrown even after
resolveProxyProviders(...)insidecls.run(...)Summary
We occasionally get
ProxyProviderNotResolvedExceptionwhen accessing a proxy provider, despite resolving it right before usage insideclsService.run(...).This happens rarely and non-deterministically in production workers (BullMQ). It looks like a race between proxy resolution and access, or a context boundary issue.
Error
What we do
Expected behavior
No exception is thrown after
await clsService.resolveProxyProviders([...])has completed within the samecls.run(...)scope.Actual behavior
Very rarely (hard to reproduce locally), an exception is thrown saying the proxy has not been resolved yet. It happens in BullMQ worker jobs.
Environment
strict: truefor proxy provider registrationClsModule.forRoot({ global: true, middleware: { mount: true } })Minimal reproduction (suggested outline)
I haven’t been able to produce a stable repro, but a flaky one could be:
clsService.run(...).strict: true.await cls.resolveProxyProviders([ProxyToken])await new Promise(r => setImmediate(r))(force a macro-task hop)Sometimes this still throws in our environment.
If there’s an official recommended pattern, I’m happy to test it and provide a full repro repo.
Workarounds tried
resolveProxyProvidersearlier in the call chain — still happens.Thanks a lot! Happy to provide more logs or build a repro if you can point me to the right pattern to ensure context consistency.