When working with AngularJS, errors in the console without a stack trace can be frustrating and difficult to debug. Common symptoms include:
- Generic error messages like “[$injector:unpr] Unknown provider” or “[$compile:ctreq] Controller required”.
- Errors without a stack trace, making it unclear where they originate.
- No line numbers pointing to the source file.
This guide walks through step-by-step methods to debug and trace AngularJS errors effectively.
1. Understanding Why Errors Lack a Stack Trace
AngularJS often suppresses detailed error logs for performance and security reasons. Common causes:
Cause | Example Error | Why It Happens |
---|---|---|
Minified Code | [$injector:modulerr] | Stack traces are removed in minified production builds |
Asynchronous Execution | No visible error in console | Errors inside $timeout , $http , or promises can be swallowed |
Silent Failures in Directives | UI not updating, but no error logs | Angular suppresses errors inside directives |
Dependency Injection Issues | [$injector:unpr] Unknown provider | Incorrect module or service injection |
Solution: Enable detailed error logging and trace errors using DevTools.
2. Enable Debug Mode for AngularJS
To get detailed error messages, disable minification and enable debug mode in AngularJS:
angular.module('myApp').config(['$compileProvider', function($compileProvider) {
$compileProvider.debugInfoEnabled(true); // Enable debugging info
}]);
- What it does:
- Adds
scope()
andisolateScope()
to elements in DevTools. - Improves error logging with meaningful messages.
- Adds
3. Using $exceptionHandler
to Log Stack Traces
By default, AngularJS catches errors and hides stack traces. Override $exceptionHandler
to log full error details:
angular.module('myApp').factory('$exceptionHandler', function() {
return function(exception, cause) {
console.error('AngularJS Error:', exception.message, '\nStack:', exception.stack);
};
});
What it does:
- Logs full stack traces for all errors.
- Helps locate the exact line and function causing the issue.
4. Catching Errors in Promises and Asynchronous Code
AngularJS errors inside $http
, $timeout
, or $q
promises might be swallowed. Wrap them in .catch()
:
$http.get('/api/data').then(function(response) {
console.log(response.data);
}).catch(function(error) {
console.error('HTTP Request Failed:', error);
});
For $timeout
:
$timeout(function() {
throw new Error('Timeout error');
}).catch(function(error) {
console.error('Timeout Error:', error);
});
What it does:
- Ensures errors are logged instead of being suppressed.
5. Debugging with console.trace()
If an error appears without a stack trace, manually insert console.trace()
before it:
console.trace('Debug Trace');
throw new Error('Manually triggered error');
What it does:
- Shows the call stack leading up to the error.
- Helps trace where an issue originated.
6. Debugging Injectors and Services
If you see [$injector:unpr] Unknown provider
, use this method to inspect dependencies:
angular.element(document).injector().annotate(myController);
What it does:
- Reveals missing or incorrectly injected dependencies.
7. Enabling Source Maps for Minified Code
If your AngularJS app uses a minified version, errors will lack readable stack traces.
Solution: Enable source maps in angular.min.js
by adding:
<script src="angular.min.js.map"></script>
- This allows DevTools to show original, unminified code.
8. Checking $digest
and $apply
Errors
If you see “[$rootScope:inprog] $digest already in progress”, force it into a $timeout
:
$timeout(function() {
$scope.$apply();
});
What it does:
- Prevents
$digest
conflicts from breaking the UI silently.
9. Debugging Directives That Fail Silently
Directives sometimes fail without errors. Use console.log()
inside the directive:
app.directive('myDirective', function() {
return {
restrict: 'E',
link: function(scope, element, attrs) {
console.log('Directive Scope:', scope);
console.log('Directive Element:', element);
}
};
});
What it does:
- Confirms if the directive initializes correctly.
10. Summary
Problem | Solution |
---|---|
No stack trace | Override $exceptionHandler |
Error inside promise | Use .catch() for $http , $timeout , $q |
Unknown provider ([$injector:unpr] ) | Use angular.element().injector().annotate() |
Digest cycle error ([$rootScope:inprog] ) | Wrap in $timeout() |
Directive failing silently | Add console.log() inside the directive |
Minified code hides errors | Enable source maps (angular.min.js.map ) |