bullmq icon indicating copy to clipboard operation
bullmq copied to clipboard

[Bug]: Error: Nest could not find BULLMQ_EXTRA_OPTIONS element (this provider does not exist in the current context)

Open miridih-jujang opened this issue 9 months ago • 8 comments

Version

v5.41.7

Platform

NodeJS

What happened?

Title: BULLMQ_EXTRA_OPTIONS provider missing after upgrading @taskforcesh/bullmq-pro to 7.32.0

Issue Description

While resolving an issue with job.getChildrenValues() (reported in #753), we upgraded from @taskforcesh/[email protected] to @taskforcesh/[email protected]. This upgrade resolved our initial problem as it includes bullMQ v5.41.7 (which contains the fix) instead of v5.31.2.

However, after the upgrade, we encountered a new error:

Steps to Reproduce

  1. Using @nestjs/bullmq with @taskforcesh/bullmq-pro
  2. Upgrade @taskforcesh/bullmq-pro from 7.24.0 to 7.32.0
  3. Start the application

Expected Behavior

The application should start normally with the BULLMQ_EXTRA_OPTIONS provider properly initialized.

Actual Behavior

The application fails to start with the error message indicating that the BULLMQ_EXTRA_OPTIONS provider is missing.

Environment

  • @taskforcesh/bullmq-pro: 7.32.0
  • bullmq: 5.41.7
  • @nestjs/common: 10.4.15
  • Node.js version: 22.8.0
  • Operating System: macOS

Additional Context

This issue emerged while fixing another problem related to job.getChildrenValues(). The previous version (7.24.0) worked without this error.

Question: When exactly does the "Error: Nest could not find BULLMQ_EXTRA_OPTIONS element" occur in the application lifecycle?

Could you confirm if this is a known issue with the latest version and provide guidance on the correct way to handle BullMQ extra options in version 7.32.0?

How to reproduce.

No response

Relevant log output


Code of Conduct

  • [x] I agree to follow this project's Code of Conduct

miridih-jujang avatar Mar 12 '25 09:03 miridih-jujang

hi @miridih-jujang, do you mean that you are using @nestjs/bullmq and no @taskforcesh/nestjs-bullmq-pro?

roggervalf avatar Mar 13 '25 01:03 roggervalf

Hi, Rogger

No, we are using @taskforcesh/nestjs-bullmq-pro. The issue occurs when using @taskforcesh/nestjs-bullmq-pro version 3.0.0 and "@taskforcesh/bullmq-pro": "7.32.0",

Best regards,

Message ID: @.***>

miridih-jujang avatar Mar 13 '25 03:03 miridih-jujang

I see, pls try using @taskforcesh/nestjs-bullmq-pro version 3.1.0 that is supporting nestjs v11. Let me know how it goes

roggervalf avatar Mar 13 '25 04:03 roggervalf

hello, Rogger

I'm still experiencing this issue after updating to @taskforcesh/nestjs-bullmq-pro version 3.1.0 and NestJS to v11 as suggested. The error "Nest could not find BULLMQ_EXTRA_OPTIONS element (this provider does not exist in the current context)" continues to occur when starting the application. I'm not sure why this issue is occurring as I've followed the upgrade instructions. Could you please help me understand what might be causing this problem? Is there a breaking change in how BullMQ Pro integrates with NestJS in these newer versions? Any guidance on how to resolve this would be greatly appreciated.

package.json

  "dependencies": {
    "@bull-board/ui": "^6.2.4",
    "@nestjs/axios": "^4.0.0",
    "@nestjs/common": "^11.0.0",
    "@nestjs/config": "^3.2.3",
    "@nestjs/core": "^11.0.0",
    "@nestjs/swagger": "^7.4.2",
    "@nestjs/terminus": "^10.2.3",
    "@taskforcesh/bullmq-pro": "7.32.0",
    "@taskforcesh/connector-pro": "^1.1.4",
    "@taskforcesh/nestjs-bullmq-pro": "^3.1.0",
    "nestjs-ddtrace": "^5.0.0",
  },
  "devDependencies": {
    "@nestjs/cli": "^11.0.0",
    "@nestjs/schematics": "^11.0.0",
    "@nestjs/testing": "^11.0.0",
  },

Best regards,

miridih-jujang avatar Mar 26 '25 05:03 miridih-jujang

hey @miridih-jujang I couldn't reproduce this error with our example repo https://github.com/taskforcesh/nestjs-bullmq-pro-example, maybe one of the other dependencies that are not part of our example could cause that error. Could you pls try to reproduce using that repo, so we can take a look and reproduce it as well.

roggervalf avatar Mar 28 '25 04:03 roggervalf

@roggervalf hello rogger

Solution for "Nest could not find BULLMQ_EXTRA_OPTIONS element" Error

We've been experiencing the "Nest could not find BULLMQ_EXTRA_OPTIONS element" error when initializing applications using @taskforcesh/nestjs-bullmq-pro v3.1.0 with @taskforcesh/bullmq-pro v7.32.0.

Problem Analysis

Through detailed debugging, we identified that the error occurs in the BullRegistrar's onModuleInit method when attempting to retrieve the BULL_EXTRA_OPTIONS_TOKEN. While examining the code at:

We found that although there's a try-catch block designed to return null when the token isn't found:

// node_modules/.pnpm/@[email protected]_@[email protected][email protected]_cla_9e8fb6d750626dc16acb1f7681597034/node_modules/@taskforcesh/nestjs-bullmq-pro/dist/bull.registrar.js

let BullRegistrar = class BullRegistrar {
    constructor(moduleRef, bullExplorer) {
        this.moduleRef = moduleRef;
        this.bullExplorer = bullExplorer;
    }
    onModuleInit() {
        const extraOptions = this.getModuleExtras(); 🔴
        if (extraOptions === null || extraOptions === void 0 ? void 0 : extraOptions.manualRegistration) {
            return;
        }
        this.register();
    }
    register() {
        return this.bullExplorer.register();
    }
    getModuleExtras() {
        try {
            const extrasToken = bull_constants_1.BULL_EXTRA_OPTIONS_TOKEN;
            return this.moduleRef.get(extrasToken, { 🔴
                strict: false,
            });
        }
        catch (_a) {
            return null;
        }
    }
};

The NestJS internal module resolution throws an UnknownElementException before reaching this catch block. The error occurs in the following execution path:

// node_modules/.pnpm/@[email protected]_@[email protected][email protected][email protected]_b33b5792bd9420a7838e1168c93cfe11/node_modules/@nestjs/core/injector/module.js

        get(typeOrToken, options = {}) {
            options.strict ??= true;
            options.each ??= false;
            return this.find(typeOrToken, options.strict 🔴
                ? {
                    moduleId: self.id,
                    each: options.each,
                }
                : options);
        }
// node_modules/.pnpm/@[email protected]_@[email protected][email protected][email protected]_b33b5792bd9420a7838e1168c93cfe11/node_modules/@nestjs/core/injector/abstract-instance-resolver.js

    find(typeOrToken, options) {
        const instanceLinkOrArray = this.instanceLinksHost.get(typeOrToken, options); 🔴
        const pluckInstance = ({ wrapperRef }) => {
            if (wrapperRef.scope === common_1.Scope.REQUEST ||
                wrapperRef.scope === common_1.Scope.TRANSIENT) {
                throw new exceptions_1.InvalidClassScopeException(typeOrToken);
            }
            return wrapperRef.instance;
        };
        if (Array.isArray(instanceLinkOrArray)) {
            return instanceLinkOrArray.map(pluckInstance);
        }
        return pluckInstance(instanceLinkOrArray);
    }
// node_modules/.pnpm/@[email protected]_@[email protected][email protected][email protected]_b33b5792bd9420a7838e1168c93cfe11/node_modules/@nestjs/core/injector/instance-links-host.js

constructor(container) {
    this.container = container;
    this.instanceLinks = new Map();
    this.initialize();
}
get(token, options = {}) {
    const instanceLinksForGivenToken = this.instanceLinks.get(token); 🔴
    if (!instanceLinksForGivenToken) {
        throw new unknown_element_exception_1.UnknownElementException(this.getInstanceNameByToken(token)); 🔴
    }
    if (options.each) {
        return instanceLinksForGivenToken;
    }
    const instanceLink = options.moduleId
        ? instanceLinksForGivenToken.find(item => item.moduleId === options.moduleId)
        : instanceLinksForGivenToken[instanceLinksForGivenToken.length - 1];
    if (!instanceLink) {
        throw new unknown_element_exception_1.UnknownElementException(this.getInstanceNameByToken(token));
    }
    return instanceLink;
}

In our debugging, we found that the instanceLinksForGivenToken Map doesn't contain the 'BULLMQ_EXTRA_OPTIONS' key, causing the exception to be thrown. This exception is being captured by our Datadog monitoring, causing alerts despite not affecting actual application functionality.

Interestingly, this issue doesn't occur in the example project you provided, suggesting it may be related to our specific configuration or environment.

Our Solution

After digging through the internal BullMQ logic, we suspected that the module configuration was missing a value for BULL_EXTRA_OPTIONS_TOKEN. We tried adding the token provider with the default value, and it coincidentally resolved the issue:

@Module({
  providers: [
    {
      provide: BULL_EXTRA_OPTIONS_TOKEN,
      useValue: {
        manualRegistration: false,
      },
    },
  ],
})

Question

Are there any potential side effects to explicitly providing this token with manualRegistration: false? If there are no adverse effects, we plan to deploy this solution to our development environment right away.

Best regard,

miridih-jujang avatar Apr 02 '25 04:04 miridih-jujang

Could you possibly provide a response regarding the discussion above?

miridih-jujang avatar Apr 23 '25 05:04 miridih-jujang

@miridih-jujang as you are just mimicking the default behaviour, i.e. manualRegistration: false, it feels quite safe to solve the issue like this. However it is concerning that this issue existed in the first place. If you ever are able to reproduce it consistently we can look deeper into it.

manast avatar Apr 23 '25 07:04 manast

"Thank you. Unfortunately, I couldn't reproduce it with the test case you provided. If it happens to reproduce in the future, I'll let you know. Thank you."

miridih-jujang avatar Apr 28 '25 04:04 miridih-jujang