#metatype is not a constructor at initialization

24 messages · Page 1 of 1 (latest)

hardy zenith
#

Hey folks,

Can someone help me out, how I can track and debug why my Application Initialization throws in init?

#
[Nest] 29  - 09/25/2023, 11:04:44 AM     LOG [NestFactory] Starting Nest application...
[Nest] 29  - 09/25/2023, 11:04:44 AM     LOG [InjectorLogger] Resolving dependency Reflector in the Reflector provider (alias)
[Nest] 29  - 09/25/2023, 11:04:44 AM     LOG [InjectorLogger] Looking for Reflector in InternalCoreModule
[Nest] 29  - 09/25/2023, 11:04:44 AM     LOG [InjectorLogger] Found Reflector in InternalCoreModule
[Nest] 29  - 09/25/2023, 11:04:44 AM   ERROR [ExceptionHandler] metatype is not a constructor
TypeError: metatype is not a constructor
    at Injector.instantiateClass (/app/node_modules/@nestjs/core/injector/injector.js:365:19)
    at callback (/app/node_modules/@nestjs/core/injector/injector.js:65:45)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)
    at Injector.resolveConstructorParams (/app/node_modules/@nestjs/core/injector/injector.js:144:24)
    at Injector.loadInstance (/app/node_modules/@nestjs/core/injector/injector.js:70:13)
    at Injector.loadProvider (/app/node_modules/@nestjs/core/injector/injector.js:97:9)
    at /app/node_modules/@nestjs/core/injector/instance-loader.js:56:13
    at async Promise.all (index 0)
    at InstanceLoader.createInstancesOfProviders (/app/node_modules/@nestjs/core/injector/instance-loader.js:55:9)
    at /app/node_modules/@nestjs/core/injector/instance-loader.js:40:13
    at async Promise.all (index 1)
    at InstanceLoader.createInstances (/app/node_modules/@nestjs/core/injector/instance-loader.js:39:9)
    at InstanceLoader.createInstancesOfDependencies (/app/node_modules/@nestjs/core/injector/instance-loader.js:22:13)
    at /app/node_modules/@nestjs/core/nest-factory.js:108:17
    at Function.asyncRun (/app/node_modules/@nestjs/core/errors/exceptions-zone.js:22:13)
    at NestFactoryStatic.initialize (/app/node_modules/@nestjs/core/nest-factory.js:106:13)
    at NestFactoryStatic.createApplicationContext (/app/node_modules/@nestjs/core/nest-factory.js:81:9)
#

Here is the stack, NEST_DEBUG didn't give me more data

novel echo
#

Well, was about to mention the debug env variable, but nevermind

hardy zenith
#

Some context:
I am using INestApplicationContext

#

yeah, debug added only the two initial infos

novel echo
#

Usually this happens when nest is calling new on something that doesn't have a constructor. Come be an invalid custom provider.

#

If you can provide a link to your git I can take a look

hardy zenith
#

That is a good pointer, I will try to find such an occurance.

#

Unfortunately it is a commercial closed-source project, can't really share the code 😦

hardy zenith
#

I managed to debug it and see that it blows up on this row: : new metatype(...instances); in injector.js.

I am trying to understand how this thing got there

#

metatype is something very odd, which is not a class 🙂

#

it's a Module ?!?

#

it is something like that:
Module {9: ƒ, id: '/app/node_modules/.../ServiceResolver.js', path: '/app/node_modules/.../providers', exports: {…}, filename: '/app/node_modules/.../providers/ServiceResolver.js', loaded: true, …}

#

ServiceResolver is a class of mine that I use to wrap around the NestApplicationContext getting of Services

#

but this class is NOT registered in the container and it is not used by any other class as dependency

#

here is the code for this class:

export class ServiceResolver<TModule> {
    private static applicationCache: Map<any, INestApplicationContext> = new Map<any, INestApplicationContext>();

    constructor(protected readonly module:TModule) {}

    public async getService<TService>(serviceToken: symbol): Promise<TService> {
        const app = await this.getOrCreateApp();
        const service = app.get<TService>(serviceToken);

        return service;
    }

    /**
     * Resolve a ID Generator.
     *
     * @param module NestJS module class that satisfies the criteria mentioned above
     * @returns An instance of the service
     */
    public getIdGenerator(): Promise<IIdGenerator> {
        return this.getService<IIdGenerator>(IIdGeneratorToken);
    }

    private async getOrCreateApp(): Promise<INestApplicationContext> {
        let app = ServiceResolver.applicationCache.get(module);

        if (app === undefined) {
            app = await NestFactory.createApplicationContext(module);
            ServiceResolver.applicationCache.set(module, app);
        }

        return app;
    }
}
#

I use it like that:
export const createIdGenerator = () => new ServiceResolver(MyNestJSModule).getIdGenerator();

#

when I do that, I get the error

#

I am stuck, I have no idea why this is trying to be created by the instantiateClass method of Injector

hardy zenith
#

Okay, so I made the methods of ServiceResolver to be static like that:

protected static async getService<TModule, TService>(module: TModule, serviceToken: symbol): Promise<TService> {
        const app = await this.getOrCreateApp(module);
        const service = app.get<TService>(serviceToken);

        return service;
    }

    private static async getOrCreateApp<TModule>(module: TModule): Promise<INestApplicationContext> {
        let app = ServiceResolver.applicationCache.get(module);

        if (app === undefined) {
            app = await NestFactory.createApplicationContext(module);
            ServiceResolver.applicationCache.set(module, app);
        }

        return app;
    }
#

And I started using it like that:
export const createIdGenerator = () => ServiceResolver.getIdGenerator(ExpenseWorkflowModule);

#

And the error is now gone and it works again. I am really curious on WHY this was happening. If someone could give me some idea, I think this can either help me NOT do stupid stuff in the future or it might be a bug for Nest?

novel echo
#

Hmm, that's really interesting. It seems like somewhere Nest thinks this class is being provided as a module or a provider (both are instantiated to read their metadatas, unless the module is a dynamic module). I'd probably need some sort of reproduction to see what;s happening though