Search code examples

Get stack trace as a string when using source map?

To get as much as possible from my errors, I want to capture stack trace to display in the browser console and also to send it to an external logger service.

The first case works fine, when I console.error(myError) the source map file is interpreted correctly by the browser and the stack trace display relevant file names.

However, when I try to get the stack trace as a string with (new Error()).stack, the filenames are not relevant:

My Error
at applicationError (http://localhost:3000/static/js/main.chunk.js:29259:
at http://localhost:3000/static/js/main.chunk.js:1624:
at onError (http://localhost:3000/static/js/0.chunk.js:82415:3)
at apiCall (http://localhost:3000/static/js/0.chunk.js:82449:12)
at async http://localhost:3000/static/js/main.chunk.js:26165:21
at async App.componentWillMount (http://localhost:3000/static/js/main.chunk.js:246:5)

How can I get the "parsed" stack trace so I can send the relevant information to my logger?

I have seen these SO questions but, while the question seems relevant at first sight, none answer my question:


  • I had the same issue, and finally, I found this npm module:

    Example from README:

    try {
      // break something
    } catch (e) {
      // pass e.stack to window.mapStackTrace
      window.mapStackTrace(e.stack, function(mappedStack) {
        // do what you want with mappedStack here
      }, {
        filter: function (line) {
          // process only sources containing `spec.js`
          return /(spec\.js)/.test(line);

    I was not able to get the above library to work, so I created a simple implementation for this myself. Might fail in some edge cases, and is probably not the most efficient, but for my needs it's enough.

    import {RawSourceMap, SourceMapConsumer} from 'source-map-js';
    const sourceMaps: {[key: string] : RawSourceMap} = {};
    async function getSourceMapFromUri(uri: string) {
      if (sourceMaps[uri] != undefined) {
        return sourceMaps[uri];
      const uriQuery = new URL(uri).search;
      const currentScriptContent = await (await fetch(uri)).text();
      let mapUri = RegExp(/\/\/# sourceMappingURL=(.*)/).exec(currentScriptContent)[1];
      mapUri = new URL(mapUri, uri).href + uriQuery;
      const map = await (await fetch(mapUri)).json();
      sourceMaps[uri] = map;
      return map;
    async function mapStackTrace(stack: string) {
      const stackLines = stack.split('\n');
      const mappedStack = [];
      for (const line of stackLines) {
        const match = RegExp(/(.*)(https?:\/\/.*):(\d+):(\d+)/).exec(line);
        if (match == null) {
        const uri = match[2];
        const consumer = new SourceMapConsumer(await getSourceMapFromUri(uri));
        const originalPosition = consumer.originalPositionFor({
          line: parseInt(match[3]),
          column: parseInt(match[4]),
        if (originalPosition.source == null || originalPosition.line == null || originalPosition.column == null) {
        mappedStack.push(`${originalPosition.source}:${originalPosition.line}:${originalPosition.column + 1}`);
      return mappedStack.join('\n');

    (You could also probably use the normal source-map library, I had to use source-map-js because of some bug which happens in my specific environment)