With version 6.3.1 injecting a repository into a service is not working anymore.
Nest can't resolve dependencies of the AuthenticationService (JwtService, ?, LogService, ConfigService). Please make sure that the argument at index [1] is available in the AuthenticationModule context. Error: Nest can't resolve dependencies of the AuthenticationService (JwtService, ?, LogService, ConfigService). Please make sure that the argument at index [1] is available in the AuthenticationModule context.
at Injector.lookupComponentInExports (PROJECT_PATH/node_modules/@nestjs/core/injector/injector.js:180:19)
at process._tickCallback (internal/process/next_tick.js:68:7)
at Function.Module.runMain (internal/modules/cjs/loader.js:757:11)
at Object.<anonymous> (PROJECT_PATH/node_modules/ts-node/src/bin.ts:157:12)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:754:12) ExceptionHandler
Authentication Service (Constructor)
export class AuthenticationService {
constructor(
private readonly jwtService: JwtService,
@InjectRepository(Customer)
private readonly customerRepository: Repository<Customer>,
private readonly logger: LogService,
private readonly config: ConfigService
) {}
}
Authentication Module
/**
* Map Passport Module to a reusable variable
*/
const passportModule = PassportModule.register({defaultStrategy: 'jwt'});
@Global()
@Module({
imports: [
passportModule,
JwtModule.registerAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
secret: config.get('JWT_SECRET_KEY')
})
}),
CustomerModule
],
providers: [AuthenticationService, AuthenticationResolver],
exports: [passportModule, AuthenticationService]
})
export class AuthenticationModule {}
Customer Module
@Module({
imports: [TypeOrmModule.forFeature([Customer]), MailModule, HttpModule],
providers: [CustomerResolver, CustomerService]
})
export class CustomerModule {}
The command ts-node -r tsconfig-paths/register src/main.ts
should start the app without any errors.
In v6.3.0 the build is still working so I guess the bug was introduced with v6.3.1
Nest version: 6.3.1
For Tooling issues:
- Node version: 10.15.3
- Platform: Mac
Others:
Same error after update version.
My case:
@Global()
@Module({
imports: [SomeModule, SomeAnotherModule],
})
export class AppModule {}
@Module({
providers: [SomeRepository],
exports: [SomeRepository],
})
export class SomeModule {}
@Module({
providers: [SomeService],
})
export class SomeAnotherModule {}
Nest can't resolve dependencies of the SomeService (?).
@kamilmysliwiec need help
v6.3.0
works fine
@raydirty your code is invalid. AuthenticationModule
doesn't contain customerRepository
- you have to add TypeOrmModule.forFeature([Customer])
(in AuthenticationModule
)
@Fyzu your code is invalid as well, SomeAnotherModule
has to import SomeModule
(or AppModule
has to re-export SomeModule
)
Hello,
Same problem for me :
import { Module } from '@nestjs/common';
import { ConfigModule } from './config/config.module';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DatabasesModule } from './databases/databases.module';
import { TerminusModule } from '@nestjs/terminus';
import { TerminusOptionsService } from './databases/terminus-options/terminus-options.service';
@Module({
imports: [
ConfigModule,
DatabasesModule,
TerminusModule.forRootAsync({
imports: [DatabasesModule],
useExisting: TerminusOptionsService,
}),
],
controllers: [
AppController,
],
providers: [
AppService,
],
})
export class AppModule {}
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { ObjectionModule } from '@willsoto/nestjs-objection';
import { ConfigModule } from '../config/config.module';
import { ConfigService } from '../config/config.service';
import { MyHealthIndicator } from './my-health-indicator/my-health-indicator';
import { TerminusOptionsService } from './terminus-options/terminus-options.service';
@Module({
imports: [
TerminusModule,
ObjectionModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: (config: ConfigService) => ({ config: config.myConfig }),
}),
],
providers: [
TerminusOptionsService,
MyHealthIndicator,
],
exports: [
TerminusOptionsService,
ObjectionModule,
],
})
export class MyModule {}
import { HealthCheckError } from '@godaddy/terminus';
import { Inject, Injectable } from '@nestjs/common';
import { HealthIndicatorResult, HealthIndicator } from '@nestjs/terminus';
import { Connection, KNEX_CONNECTION } from '@willsoto/nestjs-objection';
@Injectable()
export class MYHealthIndicator extends HealthIndicator {
constructor(@Inject(KNEX_CONNECTION) public connection: Connection) {
super();
}
async pingCheck(key: string = 'db-primary'): Promise<HealthIndicatorResult> {
try {
await this.connection.raw('SELECT 1');
return super.getStatus(key, true);
} catch (error) {
const status = super.getStatus(key, false, { message: error.message });
throw new HealthCheckError('Unable to connect to database', status);
}
}
}
Nest can't resolve dependencies of the MyHealthIndicator (?). Please make sure that the argument at index [0] is available in the MyModule context.
Platform: Windows
- @nestjs : 6.3.1
- @willsoto/nestjs-objection : 1.1.0
- node : 12.2.0
Best Regards
@kamilmysliwiec This code works with v6.2.4
so I don't think that it's invalid. Or can you tell me why this should be the case now?
Shouldn't CustomerModule
contain the CustomerRepository
which is then imported into AuthenticationModule
?
It was a bug fixed in 6.3.1
.
Shouldn't CustomerModule contain the CustomerRepository which is then imported into AuthenticationModule?
Yes, it would be the best case scenario
Yes, it would be the best case scenario
@kamilmysliwiec Then I don't understand what should be invalid in my snippet.
Your AuthenticationModule
imports CustomerModule
, which in turn imports TypeOrmModule
, but it doesn't re-export it. In Nest, providers are encapsulated in modules by default https://docs.nestjs.com/modules
The module encapsulates providers by default. This means that it's impossible to inject providers that are neither directly part of the current module nor exported from the imported modules. Thus, you may consider the exported providers from a module as the module's public interface, or API.
The most important is this part:
nor exported from the imported modules
@Global()
@Module({
imports: [SomeModule, SomeAnotherModule],
exports: [SomeModule],
})
export class AppModule {}
@Module({
providers: [SomeRepository],
exports: [SomeRepository],
})
export class SomeModule {}
@Module({
providers: [SomeService],
})
export class SomeAnotherModule {}
@kamilmysliwiec this code is valid?
@Fyzu this part should be valid. One problematic thing that I can see here is that AppModule
will actually create a circular dependency with other modules.
Do you think that my code has the same problem ?
Issue Comment
I'm not familiar with ObjectionModule
. If you prepare a sample, minimal repo with this issue, I'll try to reproduce it locally
Your
AuthenticationModule
importsCustomerModule
, which in turn importsTypeOrmModule
, but it doesn't re-export it.
@kamilmysliwiec But AuthenticationModule
contains AuthenticationService
so I don't see the need to re-export it again because CustomerRepository
is not a part of providers.
Let me give you another example with retracted names which works:
AModule
@Module({
imports: [TypeOrmModule.forFeature([A, B]), CModule],
providers: [AService]
})
export class AModule {}
AService
export class CService {
constructor(
@InjectRepository(A) private readonly aRepository: Repository<A>,
@InjectRepository(B) private readonly bRepository: Repository<B>,
@InjectRepository(C) private readonly cRepository: Repository<C>,
) {}
}
CModule
@Module({
imports: [TypeOrmModule.forFeature([C])],
providers: [CService]
})
export class CModule {}
I can also try to reproduce the bug in a minimal repo.
I'm not familiar with
ObjectionModule
. If you prepare a sample, minimal repo with this issue, I'll try to reproduce it locally
@kamilmysliwiec You can find a minimal repo here.
Let me give you another example with retracted names which works:
This example shouldn't work @raydirty
@cdupetit I pulled your repo:
ConfigModule
should export ConfigService
@willsoto/nestjs-objection
is broken. ObjectionModule
imports ObjectionCoreModule
(which is not @Global()
as in @nestjs/typeorm
for instance) and doesn't re-export it. @Module({
imports: [TypeOrmModule.forFeature([EntityA, EntityB])],
controllers: [AController],
providers: [AService, BService],
exports: [AService],
})
export class AModule{}
@Injectable()
export class BService {
constructor(
@InjectRepository(EntityB)
private readonly bRepository: Repository<EntityB>,
) {}
md5-d22bb8da60862c3d0c2b52dc092e335c
@Module({
imports: [TypeOrmModule.forFeature([EntityB])],
controllers: [BController],
providers: [BService],
exports: [BService, TypeOrmModule.forFeature([EntityB])],
})
export class BModule{}
md5-8b57e9e4bc678d548d5861739e4dfa03
@Module({
imports: [TypeOrmModule.forFeature([EntityA]), BModule],
controllers: [AController],
providers: [AService, BService],
exports: [AService],
})
export class AModule{}
I had the same problem. My project is quiet big, had to adjust up to 40 files. But I always wondered, why I could inject some intestables without being part of the module scope. I could solve everything and i was eager to do so, but I faced 1 problem.
I have some shared (global) modules for sending mails, sms, and push notifications. And all of these 3 modules are actually very similar in their structure for Module and Service. The only difference is, the Push Notification Module imports an Entity to use it's repository.
The problem I faced then: I needed to import this Entity in every module where I imported the Push Notification Module, a behavior I never faced so far. If I import a Module B inside of Module A, Module B imports everything by itself, without importing Module B imports manually in Module A.
pushnotificaiton.module.ts
import { Module, Global } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { PushNotificationLog } from '@/entities';
import { PushNotificationService } from './push-notification.service';
@Global()
@Module({
imports: [TypeOrmModule.forFeature([PushNotificationLog])],
providers: [PushNotificationService],
exports: [PushNotificationService],
})
export class PushNotificationModule {}
pushnotification.service.ts
@Injectable()
export class PushNotificationService {
@Inject('ConfigService')
private readonly config: ConfigService;
private readonly notificationRepository: BaseRepository<PushNotificationLog>;
constructor(
@InjectRepository(PushNotificationLog) notificationRepository: BaseRepository<PushNotificationLog>,
) {
this.notificationRepository = notificationRepository;
}
// 1 public send handler
}
I solved this by removing the constructor and using the repository by importing getRepository from typeorm. A solution I don't like.
@cdupetit I pulled your repo:
ConfigModule
should exportConfigService
@willsoto/nestjs-objection
is broken.ObjectionModule
importsObjectionCoreModule
(which is not@Global()
as in@nestjs/typeorm
for instance) and doesn't re-export it.
@kamilmysliwiec Thank you very much.
For anyone stumbling into here after a recent update, I followed these steps to fix my issue:
1) Updated to v6.3.1
2) Made sure to re-export modules where necessary, like the JwtModule
for example
I had updated from 6.0.4
, and there must have been a fix/change between that and 6.3.1
that required me to re-export my modules correctly.
I think that I'm hitting this .. it's rather confusing.
import { Module } from '@nestjs/common';
import { FooService } from './foo.service';
@Module({
imports: [],
providers: [FooService],
})
export class FooModule {}
and in the Bar module
import { Module } from '@nestjs/common';
import { FooModule } from '../foo/foo.module';
@Module({
imports: [ FooModule ],
providers: [BarService]
})
export class BarModule {}
so at this point, FooModule provides FooService, BarModule imports FooModule (therefore directly using it) . However, in the BarService
import { Injectable } from '@nestjs/common';
import { FooService } from '../foo/foo.service';
@Injectable()
export class BarService {
constructor(
private readonly fooService: FooService
) {}
[snip]
I get the message
Nest can't resolve dependencies of the BarService (?). Please make sure that the argument at index [0] is available in the BarModule context
Which by my reckoning, it is ... what am I doing wrong here ? Why should the FooService be exported if it's defined as being provided by FooModule ?
Before 6.3.1 I didn't have to export services .. things worked just fine.
The above code works with 6.2.4 with no errors.
@jmls
import { Module } from '@nestjs/common';
import { FooService } from './foo.service';
@Module({
imports: [],
providers: [FooService],
exports: [FooService], <---------------------
})
export class FooModule {}
Yes, but my point is that before 6.3.0 I didn't have to export the service.
Do I now have to go through all my modules and export the services? Surely
a minor upgrade shouldn't require source to be changed?
On Mon, 10 Jun 2019, 14:58 Cyril DUPETIT, notifications@github.com wrote:
@jmls https://github.com/jmls
import { Module } from '@nestjs/common';
import { FooService } from './foo.service';@Module({
imports: [],
providers: [FooService],
exports: [FooService], <---------------------
})
export class FooModule {}—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/nestjs/nest/issues/2359?email_source=notifications&email_token=AAHC546OPAVBO3VAQABBP53PZZM2DA5CNFSM4HVCAB7KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODXJ6NVA#issuecomment-500426452,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AAHC547OTTPDB7VDDGM5MILPZZM2DANCNFSM4HVCAB7A
.
@jmls you have always needed to export a service from a module in order to share it elsewhere in another module.
https://angular.io/guide/sharing-ngmodules
Nest lets you get away with a little bit more than Angular allows, like the concept of forwardRef(() => ...)
to bypass circular dependencies for example.
yeah, I've tended to use the @Injectable({ providedIn: 'root' })
in angular recently so kinda forgot that.
I was just surprised that next < 6.3.1 starts fine (and works fine), but 6.3.1 crapped out on startup
I'm also facing this issue. My app is quite big and the error nestjs gives me isn't very precise. What to do when the output gives me an UUID instead of the actual name? Like:
[ExceptionHandler] Nest can't resolve dependencies of the 158e3e7b-5bc3-4e36-803f-277ffd4c6c13 (?). Please make sure that the argument at index [0] is available in the AppModule context.
@jmls
Yes, but my point is that before 6.3.0 I didn't have to export the service. Do I now have to go through all my modules and export the services? Surely a minor upgrade shouldn't require source to be changed?
☝️ Agreed, and 👇
For anyone stumbling into here after a recent update, I followed these steps to fix my issue:
- Updated to v6.3.1
- Made sure to re-export modules where necessary, like the
JwtModule
for exampleI had updated from
6.0.4
, and there must have been a fix/change between that and6.3.1
that required me to re-export my modules correctly.
@Gustav0ar
That's interesting that you get that UUID instead of a components name, I'm not familiar with that sort of behavior, as I get the names of a class where I was being injected and a service hadn't been exported properly.
@jmls
Yes, but my point is that before 6.3.0 I didn't have to export the service. Do I now have to go through all my modules and export the services? Surely a minor upgrade shouldn't require source to be changed?
Agreed, and
For anyone stumbling into here after a recent update, I followed these steps to fix my issue:
- Updated to v6.3.1
- Made sure to re-export modules where necessary, like the
JwtModule
for exampleI had updated from
6.0.4
, and there must have been a fix/change between that and6.3.1
that required me to re-export my modules correctly.@Gustav0ar
That's interesting that you get that UUID instead of a components name, I'm not familiar with that sort of behavior, as I get the names of a class where I was being injected and a service hadn't been exported properly.
Yeah, that's the first time I got this error. Don't know how to debug it easily. I guess I'll be stuck in 6.3.0 until I can find time to dive into it.
Hey lads, I faced another global module scope issue today. But I found a solution, MAYBE it helps someone here.
6.3.1 after the scene, all dependencies used by the service layer in providers must be introduced in imports.
For anyone wondering how to resolve this for TypeORM modules:
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { FooEntity } from './foo.entity';
import { FooService } from './foo.service';
const FooEntities = TypeOrmModule.forFeature([FooEntity]);
@Module({
imports: [FooEntities],
providers: [FooService],
exports: [FooService, FooEntities], //<-re-export the entities
})
export class FooModule {}
@dhritzkiv you can actually export just TypeOrmModule
(without method call - it's not required)
Yes @dhritzkiv / @kamilmysliwiec I posted that above.
https://github.com/nestjs/nest/issues/2359#issuecomment-499661691
@Tyler-V I must have missed it!
@kamilmysliwiec Thanks for the tip!
@Tyler-V @dhritzkiv
Actually, I wanted to emphasize that you can export just TypeOrmModule
([!] without method call).
So instead of this:
exports: [BService, TypeOrmModule.forFeature([EntityB])],
you can use this:
exports: [BService, TypeOrmModule],
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Most helpful comment
@Tyler-V @dhritzkiv
Actually, I wanted to emphasize that you can export just
TypeOrmModule
([!] without method call).So instead of this:
you can use this: