Fix: Angular NullInjectorError: No provider for X
Quick Answer
How to fix Angular NullInjectorError No provider for service caused by missing providers, wrong module imports, standalone components, and lazy-loaded module issues.
The Error
Your Angular application crashes with:
NullInjectorError: R3InjectorError(AppModule)[MyService -> MyService]:
NullInjectorError: No provider for MyService!Or variations:
NullInjectorError: No provider for HttpClient!NullInjectorError: No provider for Router!NullInjectorError: R3InjectorError(Standalone[MyComponent])[MyService -> MyService]:
NullInjectorError: No provider for MyService!StaticInjectorError(AppModule)[MyComponent -> MyService]:
NullInjectorError: No provider for MyService!Angular’s dependency injection system cannot find a provider for the requested service. The service is not registered anywhere that is visible to the component requesting it.
Why This Happens
Angular uses dependency injection (DI) to provide services to components. When a component or service requests a dependency through its constructor, Angular looks for a provider that knows how to create that dependency.
If no provider is found in the injector hierarchy, Angular throws NullInjectorError.
Common causes:
- Missing
@Injectable()decorator or missingprovidedInproperty. - Service not added to
providersarray in a module or component. - Missing module import.
HttpClientneedsHttpClientModule,RouterneedsRouterModule. - Standalone component does not import the required providers.
- Lazy-loaded module has its own injector and cannot see root-level services from other lazy modules.
- Wrong import path. Importing from the wrong file or barrel export.
Fix 1: Use providedIn: ‘root’
The simplest approach. Make the service available application-wide:
Broken — missing @Injectable or providedIn:
// Service without proper decorator
export class MyService {
getData() { return []; }
}Fixed:
@Injectable({
providedIn: 'root' // Available everywhere, tree-shakable
})
export class MyService {
getData() { return []; }
}providedIn: 'root' registers the service with the root injector. It is the recommended approach for most services because:
- The service is available everywhere without manual registration.
- It is tree-shakable — if no component injects it, it is removed from the bundle.
- It creates a singleton (one instance for the entire app).
Pro Tip: Use
providedIn: 'root'for almost all services. Only use module-levelproviderswhen you need multiple instances, lazy-loaded scoping, or testing overrides.
Fix 2: Add the Service to Module Providers
If you cannot use providedIn: 'root', register in a module:
@NgModule({
providers: [MyService], // Register the service here
declarations: [MyComponent],
})
export class MyModule {}For component-level providers (new instance per component):
@Component({
selector: 'app-my-component',
template: '...',
providers: [MyService], // New instance for each component
})
export class MyComponent {
constructor(private myService: MyService) {}
}For lazy-loaded modules:
@NgModule({
imports: [CommonModule],
providers: [LazyService], // Only available within this lazy module
})
export class LazyModule {}Fix 3: Fix HttpClient Provider
The most common NullInjectorError — HttpClient needs its module:
Broken:
@Component({...})
export class MyComponent {
constructor(private http: HttpClient) {} // NullInjectorError!
}Fixed — NgModule-based app:
// app.module.ts
import { HttpClientModule } from '@angular/common/http';
@NgModule({
imports: [
BrowserModule,
HttpClientModule, // Add this!
],
})
export class AppModule {}Fixed — standalone component (Angular 15+):
// app.config.ts (Angular 17+)
import { provideHttpClient } from '@angular/common/http';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
],
};Fixed — standalone component importing directly:
@Component({
standalone: true,
imports: [HttpClientModule], // Or use provideHttpClient()
template: '...',
})
export class MyComponent {
constructor(private http: HttpClient) {}
}Common Mistake: Importing
HttpClientModulein a lazy-loaded module instead of the rootAppModule.HttpClientModuleshould be imported once at the root level. Importing it in multiple modules creates multipleHttpClientinstances, which can cause interceptor issues.
Fix 4: Fix Standalone Component Providers
Angular 14+ standalone components have their own provider scope:
Broken — standalone component missing providers:
@Component({
standalone: true,
template: '<p>{{ data }}</p>',
})
export class MyComponent {
constructor(private myService: MyService) {} // NullInjectorError if MyService not provided
}Fixed — service uses providedIn: 'root':
@Injectable({ providedIn: 'root' })
export class MyService { ... }
// No changes needed in the componentFixed — provide at the component level:
@Component({
standalone: true,
providers: [MyService],
template: '<p>{{ data }}</p>',
})
export class MyComponent {
constructor(private myService: MyService) {}
}Fixed — provide at the application level:
// main.ts
bootstrapApplication(AppComponent, {
providers: [
MyService,
provideRouter(routes),
provideHttpClient(),
],
});Fix 5: Fix Router and Forms Providers
Common built-in services that need their modules or providers:
Router:
// NgModule
@NgModule({
imports: [RouterModule.forRoot(routes)],
})
export class AppModule {}
// Standalone
bootstrapApplication(AppComponent, {
providers: [provideRouter(routes)],
});Forms:
// NgModule — import FormsModule or ReactiveFormsModule
@NgModule({
imports: [FormsModule, ReactiveFormsModule],
})
export class AppModule {}
// Standalone component
@Component({
standalone: true,
imports: [ReactiveFormsModule],
})
export class MyFormComponent {}Animations:
// NgModule
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
@NgModule({
imports: [BrowserAnimationsModule],
})
export class AppModule {}
// Standalone
import { provideAnimations } from '@angular/platform-browser/animations';
bootstrapApplication(AppComponent, {
providers: [provideAnimations()],
});Fix 6: Fix Injection Token Issues
For non-class dependencies, use InjectionToken:
import { InjectionToken } from '@angular/core';
export const API_URL = new InjectionToken<string>('API_URL');
// Provide the token
@NgModule({
providers: [
{ provide: API_URL, useValue: 'https://api.example.com' },
],
})
export class AppModule {}
// Inject the token
@Injectable({ providedIn: 'root' })
export class ApiService {
constructor(@Inject(API_URL) private apiUrl: string) {}
}For optional dependencies:
@Injectable({ providedIn: 'root' })
export class MyService {
constructor(@Optional() private logger?: LoggerService) {
// logger is null if no provider exists — no error!
}
}Fix 7: Fix Testing Providers
NullInjectorError in tests usually means the TestBed is missing providers:
describe('MyComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [MyComponent],
providers: [
MyService,
// Or use a mock:
{ provide: MyService, useValue: { getData: () => [] } },
],
imports: [
HttpClientTestingModule, // Use testing module, not HttpClientModule
],
}).compileComponents();
});
});For standalone components in tests:
await TestBed.configureTestingModule({
imports: [MyStandaloneComponent],
providers: [
{ provide: MyService, useValue: mockService },
provideHttpClient(),
],
}).compileComponents();Fix 8: Debug the Injector Hierarchy
When you cannot figure out where to provide a service:
Check the error message carefully. The injector chain shows the path:
NullInjectorError: R3InjectorError(LazyModule)[MyService -> HelperService]:
NullInjectorError: No provider for HelperService!This means MyService depends on HelperService, and HelperService has no provider.
Trace the dependency chain:
@Injectable({ providedIn: 'root' })
export class MyService {
constructor(private helper: HelperService) {} // HelperService must also be provided!
}
// Fix: Make HelperService also providedIn: 'root'
@Injectable({ providedIn: 'root' })
export class HelperService { ... }Check barrel exports:
// If you import from an index.ts barrel file:
import { MyService } from './services';
// Make sure the barrel actually re-exports it:
// services/index.ts
export { MyService } from './my.service';Still Not Working?
Check for circular dependencies. Two services that depend on each other can cause injection failures. Use forwardRef():
@Injectable({ providedIn: 'root' })
export class ServiceA {
constructor(@Inject(forwardRef(() => ServiceB)) private b: ServiceB) {}
}Check for multiple versions of Angular packages. Run npm ls @angular/core to ensure all packages use the same version.
Check your import paths. A service imported from the wrong path might not be the same class instance that is provided.
For TypeScript type errors in Angular, see Fix: TypeScript cannot find name. For module resolution issues, see Fix: TypeScript Cannot find module. For general JavaScript dependency issues, see Fix: Module not found: Can’t resolve.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Angular ExpressionChangedAfterItHasBeenCheckedError
How to fix ExpressionChangedAfterItHasBeenCheckedError in Angular caused by change detection timing issues, lifecycle hooks, async pipes, and parent-child data flow.
Fix: TypeError: x is not a function
How to fix JavaScript TypeError is not a function caused by wrong variable types, missing imports, overwritten variables, incorrect method names, and callback issues.
Fix: TypeScript Argument of type 'X' is not assignable to parameter of type 'Y' (TS2345)
How to fix TypeScript error TS2345 Argument of type is not assignable to parameter of type, covering null narrowing, union types, generics, callback types, type widening, enums, and React event handlers.
Fix: TypeScript Could not find a declaration file for module (TS7016)
How to fix the TypeScript TS7016 error 'Could not find a declaration file for module' by installing @types packages, creating declaration files, and configuring tsconfig.json.