Finding the cause of "Unknown provider" errors Finding the cause of "Unknown provider" errors angularjs angularjs

Finding the cause of "Unknown provider" errors


Angular 1.3.x has an ng-strict-di directive that is placed on the same element as the ng-app directive. This element causes your app to throw an error whenever dependencies have not been annotated. While it still doesn't give you the line number of the offending code, it does give you the function with its parameters (i.e. function($scope, myServiceName)) which is hopefully unique enough that you can find it pretty quickly in a good code edit.

A good overview of the directive: ng-strict-di.


I understand the question and I have an answer, it's only slightly convoluted.

The way I found the problem was to rename all identifiers to make them ALL unique, then you get something useful to look for in your compiled javascript which will hopefully point you towards the culprit.

download my modified version of uglify (pull request pending...)

brew install node if you don't have node installed.

./bin/uglifyjs --unique_ids original.min.js >new.min.js

Now replace your compiled js with new.min.js and load your app to reproduce the problemnow you should get a dependency injection error like n4536

If your editor is awesome with super long lines you can just load new.min.js, look for n4536 and hopefully that'll help you identify the culprit.

If not this'll work to print some context around the problem.egrep -o '.{199}n4536.{99}' new.min.js


Angular's injector has 3 ways to resolve dependencies for you:

1. Inferring dependencies from function argument names. This is most used in all angular's examples, e.g.

app.controller('MyController', function($scope, MyService) { ... });

In this case injector casts function as string, parses argument names and looks for services/factories/anything-else matching that name.

2. Inline annotations. You might also encounter this syntax:

app.controller('MyController', ['$scope', 'MyService', function($scope, MyService) { ... }]);

In this case you make it much easier for the injector, since you explicitly state names of dependencies you require. The names are enclosed in quotes and js minifiers do not modify strings in code.

3. Inline annotations as property. If you define your controllers as functions, you might set annotations in special property $inject:

function MyController($scope, MyService) {...}MyController.$inject = ['$scope', 'MyService'];

In this case we also explicitly state dependencies.

My guess is you're using the solution no. 1. Once minifier changes names of your implicitly defined dependencies, injector no longer knows, what are your function's dependencies. To overcome this you should use 2nd or 3rd way of annotating dependencies.