angular/angular.js · error · Error
Too many components found
Error message
Too many components found
What it means
$componentController filters the directives registered under a name to component-shaped ones (controller + controllerAs + restrict 'E'). If MORE than one definition survives — multiple loaded modules (including transitively pulled-in ones) each define a directive/component with that name — the mock cannot decide which controller to instantiate and throws 'Too many components found'.
Source
Thrown at src/ngMock/angular-mocks.js:2550
* @return {Object} Instance of requested controller.
*/
angular.mock.$ComponentControllerProvider = ['$compileProvider',
function ComponentControllerProvider($compileProvider) {
this.$get = ['$controller','$injector', '$rootScope', function($controller, $injector, $rootScope) {
return function $componentController(componentName, locals, bindings, ident) {
// get all directives associated to the component name
var directives = $injector.get(componentName + 'Directive');
// look for those directives that are components
var candidateDirectives = directives.filter(function(directiveInfo) {
// components have controller, controllerAs and restrict:'E'
return directiveInfo.controller && directiveInfo.controllerAs && directiveInfo.restrict === 'E';
});
// check if valid directives found
if (candidateDirectives.length === 0) {
throw new Error('No component found');
}
if (candidateDirectives.length > 1) {
throw new Error('Too many components found');
}
// get the info of the component
var directiveInfo = candidateDirectives[0];
// create a scope if needed
locals = locals || {};
locals.$scope = locals.$scope || $rootScope.$new(true);
return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
};
}];
}];
/**
* @ngdoc module
* @name ngMock
* @packageName angular-mocks
* @description
*View on GitHub (pinned to d8f77817eb)
Solutions
- Rename one of the colliding components/directives so the name is unique across all loaded modules.
- Stop loading the module that redefines the name in this test's beforeEach(module(...)) chain.
- If you only need the controller logic, bypass the ambiguity: instantiate a specific controller with $controller('RatingCtrl', ...) instead of $componentController.
Example fix
// before
// app module
angular.module('app').component('tabs', {controller: AppTabsCtrl, controllerAs: '$ctrl'});
// third-party module, also loaded in the test
angular.module('ui.lib').component('tabs', {controller: LibTabsCtrl, controllerAs: '$ctrl'});
$componentController('tabs'); // throws: Too many components found
// after
angular.module('app').component('appTabs', {controller: AppTabsCtrl, controllerAs: '$ctrl'});
// update the template <app-tabs> and the call:
$componentController('appTabs'); Defensive patterns
Strategy: validation
Validate before calling
// Detect name collisions before instantiating
inject(function($injector) {
var candidates = $injector.get('tabs' + 'Directive').filter(function(d) {
return d.controller && d.controllerAs && d.restrict === 'E';
});
if (candidates.length !== 1) {
throw new Error('Expected exactly 1 component named tabs, found ' + candidates.length);
}
}); Prevention
- Prefix in-house component names (appTabs vs tabs) to avoid third-party collisions.
- Audit loaded modules when adding a UI library: search for duplicate .component/.directive names.
- Delete old definitions after renames instead of leaving both registered.
When it happens
Trigger: Two modules both loaded in the test define the same name as component/directive (e.g., your app's 'tabs' and a UI library's 'tabs'); a component plus a hand-written directive with the same name that also has controller, controllerAs and restrict 'E'; accidentally registering the same component in two modules during a refactor/rename.
Common situations: Loading a third-party module that collides with an in-house component name; test bundles loading both app.module and a feature module that re-exports the same component; duplicated directive definitions left behind after renaming.
Related errors
- No component found
- No deferred tasks to be flushed
- Deferred tasks to flush ({}): {}
- Expected $log to be empty! Either a message was logged unexp
- No pending animations ready to be closed or flushed
AI-assisted analysis of angular/angular.js@d8f77817eb (2026-08-21).
Data as JSON: /api/errors/0858ce47047e69c2.
Report an issue: GitHub.