Read your production Angular Errors like a pro

Evgeny Fedorenko
Angular In Depth
Published in
4 min readFeb 13, 2020

AngularInDepth is moving away from Medium. More recent articles are hosted on the new platform inDepth.dev. Thanks for being part of indepth movement!

We all want to build bug-free applications. We also know that it is not possible. Therefore the best we can do when we encounter an error is to interpret it as fast as we can and push the fix.

I am sure this one looks familiar:

This is a TypeError thrown from the Angular application which can be seen in the Chrome Developer Tools console tab. Let’s analyze it to understand what is going on:

  1. The error tells us that there is an attempt to access the property ‘value’ of some variable which at that time holds a null value. If this is not enough for us to know where this code is then we need to dig deeper (this would be the case when ‘value’ property name is too generic and there are multiple places where this could be happening)
  2. at t.<anonymous> main-es2015.d97d995449352dcdcf91.js:1 is supposed to tell us where the error has occurred in the call stack. Sadly, it does not help much. Since this is production all file/method names are minified and are not readable. Also, the entire file is composed of a single line of massive code chunk therefore reference to the first line in the call stack is also useless.

When we generate Angular application for production the code gets optimized — bundled, minified and uglified.

When we ship the code to production we generally don’t want to include source-maps in the build. The above example is no exception. So even if we get lucky and witness this error (which is not always a case because not all users report errors) we are still clueless about it due to the debugging limitations in prod builds.

Are we doomed?

There are a few problems we need to solve here. Let’s tackle them one by one. For now, why don’t we figure out how can we collect all instances of such errors and store them for later analysis?

Logging browser exceptions

Angular provides us with a hook for centralized exception handling called ErrorHandler. To intercept error handling, we can write a custom exception handler that replaces ErrorHandler default implementation. Consider this example:

class MyErrorHandler implements ErrorHandler {....handleError(error) {
this.logger.error(error);
}
....
}
@NgModule({ providers: [{
provide: ErrorHandler,
useClass: MyErrorHandler
}]
})
class MyModule {}

This is a simple implementation of our ErrorHandler which uses a logger service to send the error via HTTP POST request to our backend. The error here is a Javascript Error. We are interested in error.stack property.

The non-standard stack property of Error objects offer a trace of which functions were called, in what order, from which line and file, and with what arguments. The stack string proceeds from the most recent calls to earlier ones, leading back to the original global scope call.

This is how the last element of the stack trace looks when logged in the Browser console:

main-es2015.d97d995449352dcdcf91.js:1

We can see here a lineNumber. The other important property is the columnNumber. The console log does not show it. When dealing with production code it is very important to have that information so that we understand the origin of the error.

Here is how the stack property looks like when being inspected in the Chrome debugger (to achieve this output I hovered over the stack property of the error variable):

292908 here is the much neededcolumnNumber. And here is why.

Reading production error stack trace

Now after we have the information about the error which consists of fileName, lineNumber and columnNumber we can interpret its location using source-map-cli tool. It is a command-line interface to the source-map module.

Here is how it can be used:

resolve [options] <uri> <line> <column>

The resolve command accepts a source map (either a path or a URL), a line and column and returns the original source file name, line and column, along with a context (usually the name of the variable or function).

Since we don’t have source-maps generated we need to build them:

ng build --prod --sourceMap=true

This command will produce the build along with the source map files. After that we can run this command (please note, the source map file name will be different from the original corresponding source file b/c new build generates new hash):

source-map resolve dist/main-es2015.0cd3209b74d20b15dbfc.js.map 1 292908

And finally — it will give you the filename and location of the error:

Maps to webpack:///src/app/app.component.ts:33:15 (value)    return obj.value;               ^

Conclusion

In this short article we learned how to read our production logs.

  1. We need to store the errors so later we can handle them.
  2. We can use a nice tool like source-map-cli to get the information about the error in the production optimized source code.

Thank you.

If you liked this article follow me on twitter at @e_fedorenko

--

--

Evgeny Fedorenko
Angular In Depth

Professional procrastinator. Love the web, sharing the love. Slooooowly…