Diagnosing AngularJS $injector:unpr Unknown Provider Errors
A step-by-step diagnostic guide for AngularJS $injector:unpr unknown provider errors: recognizable symptoms, cause table, ordered checks, targeted fixes, and escalation criteria for AngularJS 1.x applications.
05 Aug 2025, 00:45 UTC

Recognizable Condition
AngularJS logs Error: [$injector:unpr] Unknown provider: <name>Provider <- <name> immediately after bootstrap or controller instantiation. The dependency injection (DI) system halts, leaving the component or service uninitialized. You will see this in the browser console, often paired with a stack trace pointing to the failing injector call.
Cause and Diagnostic Reference
| Symptom | Likely Cause | Quick Verification |
|---|---|---|
| Error names a service you wrote | Missing module dependency in angular.module('app', ['missingModule']) | Check the module declaration array |
| Error appears only after minification | Constructor parameters lost their names; no inline array or $inject annotation | Compare minified vs. unminified source |
| Error references a third-party service | Typo in service name or provider script loads after consumer | Inspect script order in Network tab |
| Error during service-to-service injection | Circular dependency between two services | Search for mutual factory/service references |
Error names a provider that returns undefined | Factory function missing return statement | Review factory body for explicit return |
Ordered Diagnostic Checks
-
Confirm module identity. The string passed to
ng-app(orangular.bootstrap) must exactly match the first argument ofangular.module('name', []). A mismatch creates a new empty module instead of extending yours.
Run in console:<!-- index.html --> <html ng-app="myApp"> // app.js angular.module('myApp', ['ngRoute']); // must be 'myApp'angular.module('myApp')._invokeQueue.length— zero means the module is empty. -
Verify script load order. Open the Network tab, filter by JS, and ensure every provider script appears before the consumer script and before
ng-appbootstrap. Deferred or async scripts that load after bootstrap will not register in time. -
Inspect minification annotations. Controllers, services, and factories must use inline array annotation or
$injectproperty when minified. AngularJS 1.2+ supports both.
If you see// Before minification — safe app.controller('UserCtrl', ['$scope', '$http', function($scope, $http) { // ... }]); // Equivalent $inject form function UserCtrl($scope, $http) { /* ... */ } UserCtrl.$inject = ['$scope', '$http']; app.controller('UserCtrl', UserCtrl);function(a,b)in the minified bundle without a preceding string array, annotation is missing. -
Check spelling against registration. The provider name in the error (before
Provider) must match the exact string used in.factory('exactName', ...)or.service('exactName', ...). Case sensitivity matters. -
Trace circular references. Search for two services injecting each other directly. Example:
Break the cycle by injectingapp.service('Auth', ['User', function(User) { /* uses User */ }]); app.service('User', ['Auth', function(Auth) { /* uses Auth */ }]);$injectorlazily in one service or extracting shared logic into a third service.
Fixes Mapped to Findings
| Finding | Fix | Code Example |
|---|---|---|
| Missing module in dependency array | Add the module name to the main module's requires array | angular.module('app', ['ngRoute', 'ui.bootstrap', 'myFeature']) |
| Unannotated parameters after minification | Rewrite using inline array annotation (preferred) or $inject |
See step 3 example above |
| Typo in service name | Correct the spelling in the injection array to match registration | Change 'userServcie' to 'userService' |
| Provider script loads too late | Move the provider's <script> tag above the consumer and bootstrap |
Order: angular.js → providers → consumers → app bootstrap |
| Circular dependency | Inject $injector and call get() at runtime, or refactor to a shared service |
app.service('Auth', ['$injector', function($inj) { var User = $inj.get('User'); }]) |
| Factory returns undefined | Add explicit return statement in factory function |
.factory('api', function() { return { get: fn }; }) |
Escalation Criteria
Stop debugging and escalate when:
- All five checks pass but the error persists — suspect a third-party module built for a different AngularJS version.
- The offending provider comes from a library incompatible with AngularJS 1.8.x (the final LTS release).
- Workarounds such as lazy
$injectorinjection proliferate, indicating architectural decay.
At this point, evaluate whether to pin the third-party dependency to a compatible version, fork and patch it, or plan migration to Angular (v2+). Patching DI internals is not sustainable.
Version-Sensitive Behavior
- Inline array annotation (
['$scope', fn]) is supported from AngularJS 1.2 onward. component()introduced in 1.5 follows identical DI rules; its controller function still requires annotation for minification safety.- Minification handling has not changed across 1.x LTS releases.
Practical Verification Steps
- Reproduce with the unminified
angular.js(notangular.min.js) to get readable stack traces. - In the browser console, run:
If this throws, the service is not registered in the injector at all.angular.injector(['ng', 'myApp']).get('myService') - Confirm every module script appears in the Network tab before the
ng-appbootstrap timestamp.
Limitations and Risks
- Do not edit minified production bundles directly; rebuild from source with
ng-annotate(deprecated but functional) or explicit inline annotations. - Assuming provider availability before
angular.bootstrapcompletes is unsafe; script load order is deterministic only when scripts are synchronous and ordered. - Lazy
$injectorinjection masks circular-dependency design problems; prefer refactoring shared logic into a dedicated service. - This guide assumes AngularJS 1.2+ and access to browser developer tools (Console, Network, Sources).
Quick Result Check
After applying a fix, reload the page with the unminified AngularJS file. The console should show no [$injector:unpr] errors, and the component that previously failed should initialize. If the error shifts to a different provider, repeat the diagnostic from step 1 for the new name.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.