Skip to content

Fix: Angular NullInjectorError: No provider for X

FixDevs ·

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 missing providedIn property.
  • Service not added to providers array in a module or component.
  • Missing module import. HttpClient needs HttpClientModule, Router needs RouterModule.
  • 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-level providers when 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 NullInjectorErrorHttpClient 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 HttpClientModule in a lazy-loaded module instead of the root AppModule. HttpClientModule should be imported once at the root level. Importing it in multiple modules creates multiple HttpClient instances, 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 component

Fixed — 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.

F

FixDevs

Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.

Was this article helpful?

Related Articles