Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

request property in a service class is undefined after v9.3.1 #11002

Closed
4 of 15 tasks
karam-mustafa opened this issue Feb 1, 2023 · 62 comments
Closed
4 of 15 tasks

request property in a service class is undefined after v9.3.1 #11002

karam-mustafa opened this issue Feb 1, 2023 · 62 comments

Comments

@karam-mustafa
Copy link

karam-mustafa commented Feb 1, 2023

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

I have a simple constrictor for a service class as following

constructor( @Inject(REQUEST) public readonly request: Request, runAuthDependincies: Boolean = true, )

after you had released v9.3.1 this request is undefined

Minimum reproduction code

https://codesandbox.io/s/withered-monad-zgg1nu

Steps to reproduce

just updating the packages to 9.3.1

Expected behavior

The request property should not be undefined as before

Package

  • I don't know. Or some 3rd-party package
  • @nestjs/common
  • @nestjs/core
  • @nestjs/microservices
  • @nestjs/platform-express
  • @nestjs/platform-fastify
  • @nestjs/platform-socket.io
  • @nestjs/platform-ws
  • @nestjs/testing
  • @nestjs/websockets
  • Other (see below)

Other package

No response

NestJS version

9.3.1

Packages versions

"@hapi/hapi": "^21.0.0",
        "@hapi/joi": "^17.1.1",
        "@nestjs-modules/mailer": "^1.8.1",
        "@nestjs/common": "^9.0.0",
        "@nestjs/config": "^2.2.0",
        "@nestjs/core": "^9.0.0",
        "@nestjs/jwt": "^9.0.0",
        "@nestjs/passport": "^9.0.0",
        "@nestjs/platform-express": "^9.0.0",
        "apollo-server-express": "^3.11.1",
        "apollo-server-plugin-base": "^3.7.1",
        "class-transformer": "^0.5.1",
        "class-validator": "^0.13.2",
        "dotenv": "^16.0.3",
        "googleapis": "^109.0.1",
        "nodemailer": "^6.9.0",
        "passport-google-oauth20": "^2.0.0",
        "reflect-metadata": "^0.1.13",
        "rimraf": "^3.0.2",
        "rxjs": "^7.2.0"

Node.js version

16.3

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

@karam-mustafa karam-mustafa added the needs triage This issue has not been looked into label Feb 1, 2023
@karam-mustafa karam-mustafa changed the title header is undefined after v9.3.1 request property in a service class is undefined after v9.3.1 Feb 1, 2023
@micalevisk
Copy link
Member

micalevisk commented Feb 1, 2023

  • are you using durable providers?
  • did you have some ContextIdStrategy? show us

@jmcdo29
Copy link
Member

jmcdo29 commented Feb 1, 2023

Please provide a minimum reproduction repository (Git repository/StackBlitz/CodeSandbox project).

why reproductions are required

@micalevisk
Copy link
Member

@karam-mustafa read this: #10809

@karam-mustafa
Copy link
Author

  • are you using durable providers?
  • did you have some ContextIdStrategy? show us

here is my basic service class

import {
  google,
  Auth,
  GoogleApis,
  admin_directory_v1,
  drive_v3,
  drive_v2,
} from 'googleapis';

import { Request } from 'express';
import { Inject, Injectable, Scope } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';

@Injectable({ scope: Scope.REQUEST })

export class BaseGoogleServices {
  requestProp: Request;

  constructor(
    @Inject(REQUEST) public readonly request: Request,
    runAuthDependincies: Boolean = true,
  ) {
       this.requestProp = request;
    }

    if (runAuthDependincies) {
      this.resolveAuthDependencies();
    }
  }

  resolveAuthDependencies() {
    // do some code
  }
}

@jmcdo29
Copy link
Member

jmcdo29 commented Feb 1, 2023

I'll say it one more time.

Please provide a minimum reproduction repository (Git repository/StackBlitz/CodeSandbox project).

why reproductions are required

Otherwise, please use our Discord channel (Support). We are using GitHub to track Bug Reports, Feature Requests, and Regressions.

@karam-mustafa
Copy link
Author

I'll say it one more time.

Please provide a minimum reproduction repository (Git repository/StackBlitz/CodeSandbox project).

why reproductions are required

Otherwise, please use our Discord channel (Support). We are using GitHub to track Bug Reports, Feature Requests, and Regressions.

https://codesandbox.io/s/withered-monad-zgg1nu

@jmcdo29
Copy link
Member

jmcdo29 commented Feb 1, 2023

Your reproduction doesn't start. @nestjs/core and @nestjs/common are missing and the web preview stays on a 502 bad gateway screen. Please don't make us do the work of fixing your reproduction just so we can see your bug.

@micalevisk
Copy link
Member

image

I just tested your repro (after minor changes to make it minimal as possible while valid). Your repro doesn't reproduces the issue.

full code
// main.ts
import { NestFactory } from '@nestjs/core';
import type { NestExpressApplication } from '@nestjs/platform-express';
import { AppModule } from './app.module';
 
async function bootstrap() {
  const app = await NestFactory.create<NestExpressApplication>(AppModule);
  await app.listen(process.env.PORT || 3000);
}
bootstrap();
import { Module, Controller, Get, Inject, Injectable, Scope } from '@nestjs/common';
import { REQUEST } from '@nestjs/core';
import { Request } from 'express';


@Injectable({ scope: Scope.REQUEST })
class Foo {
  constructor(
    @Inject(REQUEST) public readonly request: Request,
  ) {
    console.log('====================================');
    console.log(typeof request === 'undefined'); // false
    console.log('====================================');
  }
}


class AppService extends Foo {
  constructor(
    @Inject(REQUEST) public readonly request: Request,
  ) {
    super(request)
    console.log(typeof request === 'undefined'); // false
  }
}



@Controller()
class AppController {
  constructor(private readonly appService: AppService) {}
  @Get()
  getHello(): string {
    return 'ok'
  }
}



@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

@karam-mustafa
Copy link
Author

Your reproduction doesn't start. @nestjs/core and @nestjs/common are missing and the web preview stays on a 502 bad gateway screen. Please don't make us do the work of fixing your reproduction just so we can see your bug.

Sorry for this confusion, I will let you know again when the repo could reproduce the issue, thanks for your patience

@davidzwa
Copy link

davidzwa commented Feb 2, 2023

Having the same issue:

  • The request is undefined when injecting (using @Inject(REQUEST)) in a service which is marked as scope.REQUEST
  • After the 9.3.1 update this problem suddenly occurred
  • After reverting the Nest packages back to 9.2.1 the problem dissappears
  • I cant get it reproduced in CodeSandbox, which suggests to me another dependency in my module is causing this problem. I am not using durability in my project (nor in the sandbox)

https://codesandbox.io/p/sandbox/runtime-star-dpm9rv?file=%2Fsrc%2Fapp.module.ts&selection=%5B%7B%22endColumn%22%3A1%2C%22endLineNumber%22%3A11%2C%22startColumn%22%3A1%2C%22startLineNumber%22%3A11%7D%5D

  • I simplified the code of @karam-mustafa without gateway 502 error
  • Removed noise or unused packages irrelevant to the problem
  • I updated and pinned all the packages to the latest versions (that I have locally as well)

Any tips on how I can help you refine this issue further from this point?

@kamilmysliwiec
Copy link
Member

@micalevisk so I'm guessing this might be related to this PR #10809 (perhaps isDependencyTreeDurable returns true even though the tree isn't durable for some edge-case scenarios?

@Drugg0ff
Copy link

Drugg0ff commented Feb 2, 2023

Same problem. Error when migrating from 9.2.1 to 9.3.1 - UnhandledPromiseRejectionWarning: TypeError: this.graphInspector.insertEntrypointDefinition is not a function

@micalevisk
Copy link
Member

@Durairaj that's another one. Upgrade your @nestjs/core to 9.3

@micalevisk
Copy link
Member

micalevisk commented Feb 2, 2023

@kamilmysliwiec since no one shared any repro, I guess we should revert that PR for now.

@micalevisk
Copy link
Member

hi @davidzwa is there any chance to share your code in a private repository with me?

or maybe you can see what was done at PR #10809 (which is pretty small) and try to debug it locally yourself :)

@kamilmysliwiec
Copy link
Member

#11018

@davidzwa
Copy link

davidzwa commented Feb 2, 2023

@micalevisk in the 9.2.1 edition neither MiddlewareModule::bindHandler or MiddlewareModule::registerHandler function is being called (no breakpoints or console logs that I added seem to trigger in the transpiled js code of nestjs). These are the places your changes seem to reside.
I might try 9.3.1 soon for comparison.

Im not in the position to share the repo. Will keep you posted if I have more info to share.

@micalevisk
Copy link
Member

micalevisk commented Feb 2, 2023

@davidzwa another thing you could do: define the env var NEST_DEBUG=true and see if you got occurrences of 'durable' in your logs

@davidzwa
Copy link

davidzwa commented Feb 2, 2023

That tip is really nice! I think this extract might help you:

[server-nest] Info      02/02/2023, 17:06:17 [InstanceWrapper] PrinterController introspected as request-scoped - {} +0ms
[server-nest] Info      02/02/2023, 17:06:17 Starting server at port 4000 - {} +0ms
[server-nest] Info      02/02/2023, 17:06:17 [PrinterGateway] Gateway initialized - {} +1ms
[server-nest] Info      02/02/2023, 17:06:17 [WebSocketsController] PrinterGateway subscribed to the "init-request" message - {} +0ms
[server-nest] Info      02/02/2023, 17:06:17 [AdminGateway] SocketIO AdminUI enabled. This can be disabled with: 'SOCKETIO_ADMINUI_ENABLED=false' - {} +0ms
[server-nest] Info      02/02/2023, 17:06:17 [InstanceWrapper] PrinterController introspected as durable - {} +5ms
[server-nest] Info      02/02/2023, 17:06:17 [InstanceWrapper] PrinterFileController introspected as durable - {} +0ms

Before the listen call we see PrinterController introspected as request-scoped, immediately after the listen(...) call the logs show PrinterController introspected as durable. This is the function that prints that (just making sure that I follow what is happening):

public isDependencyTreeStatic(lookupRegistry: string[] = []): boolean {

@micalevisk
Copy link
Member

great, thanks

now could you please remove the !item.isDependencyTreeStatic() condition
from L121 node_modules/@nestjs/core/injector/instance-wrapper.js

const isTreeNonDurable = this.introspectDepsAttribute(
(collection, registry) =>
collection.some(
(item: InstanceWrapper) =>
!item.isDependencyTreeStatic() &&
!item.isDependencyTreeDurable(registry),
),
lookupRegistry,
);

I'm suggesting this because that was another change introduced in 9.3.1 (PR #10698)

@davidzwa
Copy link

davidzwa commented Feb 2, 2023

Problem's gone with your suggestion. (FYI: my post above was 9.3.1 ofcourse)

[server-nest] Info      02/02/2023, 17:58:08 [InstanceWrapper] PrinterFileController introspected as request-scoped - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [InjectorLogger] Looking for automapper:nestjs:default in SentryCoreModule - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [InjectorLogger] Looking for automapper:nestjs:default in TypeOrmCoreModule - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [InjectorLogger] Looking for automapper:nestjs:default in AutomapperModule - {} +0ms
[server-nest] Info      02/02/2023, 17:58:08 [InjectorLogger] Found automapper:nestjs:default in AutomapperModule - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [InjectorLogger] Looking for automapper:nestjs:default in CacheModule - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [InjectorLogger] Looking for automapper:nestjs:default in SafeEventEmitterModule - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [InjectorLogger] Looking for automapper:nestjs:default in OidcModule - {} +0ms
[server-nest] Info      02/02/2023, 17:58:08 [InstanceWrapper] PrinterController introspected as request-scoped - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 Starting server at port 4000 - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [PrinterGateway] Gateway initialized - {} +0ms
[server-nest] Info      02/02/2023, 17:58:08 [WebSocketsController] PrinterGateway subscribed to the "init-request" message - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [AdminGateway] SocketIO AdminUI enabled. This can be disabled with: 'SOCKETIO_ADMINUI_ENABLED=false' - {} +1ms
[server-nest] Info      02/02/2023, 17:58:08 [UserModule] Admin user found - skipping automatic creation step - {} +11ms
[server-nest] Info      02/02/2023, 17:58:08 [SettingsService] Cached entity with key settings.1 and id 1 - {} +19ms

No more 'introspected as durable for the PrinterFileController nor PrinterController.

@micalevisk
Copy link
Member

@kamilmysliwiec ok so here we go

Can we revert #10698 and then revert #11018 ?

@vizio360
Copy link
Contributor

vizio360 commented Feb 2, 2023

Right, will look at it as well as soon as I get some free time. Disappointed my first contribution broke stuff...

@vizio360
Copy link
Contributor

vizio360 commented Feb 2, 2023

just reading through the thread, @davidzwa the example on CodeSandbox does it break when you run it locally?

@micalevisk
Copy link
Member

@vizio360 it doesn't

we have no repro so far

@vizio360
Copy link
Contributor

vizio360 commented Feb 2, 2023

@davidzwa could you check the dependencies chain of PrinterFileController and PrinterController and list them out?
What I'm interested in is the scopes of each injected dependency and their dependencies.

Hopefully you don't have too many :)

@SocketSomeone
Copy link
Contributor

Any pipes with scope REQUEST doesnt work 👍🏻

@micalevisk
Copy link
Member

https://automapperts.netlify.app/

@davidzwa
Copy link

davidzwa commented Feb 3, 2023

https://www.npmjs.com/package/@automapper/nestjs
https://github.com/nartc/mapper/tree/main

@davidzwa
Copy link

davidzwa commented Feb 3, 2023

this.durable === undefined

I still hope you agree that this.durable !== false should not result in true if there is clearly no durability (durable: undefined). That's an edge case in my view.

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

wondering if we could replace that with this.isTreeDurable = !isTreeNonDurable && this.durable

@kamilmysliwiec
Copy link
Member

Can we revert #10698 and then revert #11018 ?

#11018 reverted. Now - not sure what we should do about this one #10698 - sounds like this issue only occurs when AutoMapper is included in the project?

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

@karam-mustafa are you also using AutoMapper?

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

@davidzwa I managed to force the error caused by this.durable !== false. Repro repo here https://github.com/vizio360/nestJSDurableProvidersIssue/tree/nonExplicitDurability with description and instructions in the README file.
But this is only when using a ContextIdStrategy.

Will create an issue, even though this is tested on nestjs 9.3.1 and we still don't know if the PRs that have been reverted can be reapplied. I think it will depend on what we understand about the issue with AutoMapper.

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

Can we revert #10698 and then revert #11018 ?

#11018 reverted. Now - not sure what we should do about this one #10698 - sounds like this issue only occurs when AutoMapper is included in the project?

@kamilmysliwiec I will try and get automapper in my repro repo, and see if I can figure out what the issue is.

@karam-mustafa
Copy link
Author

@karam-mustafa are you also using AutoMapper?

I didn't install it before

@micalevisk
Copy link
Member

micalevisk commented Feb 3, 2023

@karam-mustafa it's working now in v9.3.2 right? nvm, it shouldn't

@kamilmysliwiec
Copy link
Member

@micalevisk note - I didn't revert #10698 yet

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

@kamilmysliwiec @micalevisk just experienced the problem in our code base with nestjs 9.3.2 and we do not use AutoMapper.

@micalevisk
Copy link
Member

micalevisk commented Feb 3, 2023

that's expected as your PR wasn't reverted yet (I thought it was :p).

So now you have a reproduction of that bug that you can work with, right?

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

Correct, and we are not using ContextIdStrategy, so it sounds like the same issue @davidzwa is having.

@davidzwa
Copy link

davidzwa commented Feb 3, 2023

Just pitching in shortly, I was using 2 Crud mixins in my controller. It was too late in the night for me to eliminate that as a cause

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

@kamilmysliwiec @micalevisk so in 9.3.2 11018 is out while 10698 is still included?

@micalevisk
Copy link
Member

@vizio360 exactly. 9.3.2 doesn't fix the bug introduced in 9.3.0

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

@davidzwa ok, can you reintroduce AutoMapper and make this change this.isTreeDurable = !isTreeNonDurable && this.durable in the instance-wrapper.js file? and try it?

isDependencyTreeDurable(lookupRegistry = []) {
        if (!(0, shared_utils_1.isUndefined)(this.isTreeDurable)) {
            return this.isTreeDurable;
        }
        if (this.durable === true) {
            this.isTreeDurable = true;
            this.printIntrospectedAsDurable();
            return this.isTreeDurable;
        }
        const isStatic = this.isDependencyTreeStatic();
        if (isStatic) {
            return false;
        }
        const isTreeNonDurable = this.introspectDepsAttribute((collection, registry) => collection.some((item) => !item.isDependencyTreeStatic() &&
            !item.isDependencyTreeDurable(registry)), lookupRegistry);
        this.isTreeDurable = !isTreeNonDurable && this.durable;   //<--HERE
        if (this.isTreeDurable) {
            this.printIntrospectedAsDurable();
        }
        return this.isTreeDurable;
    }

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

@kamilmysliwiec @micalevisk

I think I found the possible problem, at least in our code base it seems to be with pipes as they are marked as isTreeStatic = true.
that obviously will return true when calling isDependencyTreeStatic() in instance-wrapper: isDependencyTreeDurable -> introspectDepsAttribute()

Adding {scope: Scope.REQUEST} to the Pipe makes it work.

our controller:

    @Get('/ourRoute')
    async ourRoute(
        @Request() req,
        @Query('additionalData', AdditionalDataPipe) additionalData?: AdditionalDataEnum[]
    ): Promise<GetCurrentUserResponse> {

The fixed Pipe:

@Injectable({
    scope: Scope.REQUEST,
})
export class AdditionalDataPipe implements PipeTransform<string, AdditionalDataEnum[]> {

So, not sure if I need to guard against Pipes and treat them differently, I think I need to dig deeper.

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

and I think I got a test reproducing the issue

describe.only('when wrapper is non static and dep is static', () => {
          it('should return false', () => {
            const wrapper = new InstanceWrapper({ scope: Scope.REQUEST });
            wrapper.addCtorMetadata(0, new InstanceWrapper());
            expect(wrapper.isDependencyTreeDurable()).to.be.false;
          });
        });

this fails. It should return false.

@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

possible fix in the PR above

@micalevisk micalevisk added type: bug 😭 and removed needs triage This issue has not been looked into labels Feb 3, 2023
@vizio360
Copy link
Contributor

vizio360 commented Feb 3, 2023

nope more investigation needed...

@vizio360
Copy link
Contributor

vizio360 commented Feb 4, 2023

ok got more understanding of the issue, I started commenting on the PR itself.

@vizio360
Copy link
Contributor

vizio360 commented Feb 4, 2023

So I think I got to the bottom of it, and the PR #11041 has been updated. I've also added a diagram to explain the problem.

@kamilmysliwiec
Copy link
Member

Let's track this here #11041

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

No branches or pull requests

8 participants