Sourcemaps

Raygun will automatically give you complete stack traces and error occurrence data from your minified JavaScript. We support both public and private source maps.

Minified files save space and make loading of pages faster, but sometimes make it hard for Raygun to pull out the error details and show a readable stack trace. To counteract this we need customers to upload their source maps to Raygun or make them available for us to fetch from their application, so we can do some magic to pull out the right information and show a readable stacktrace.

Some security conscious companies will not want to upload source maps to us or make them publicly accessible. For this we can support private source maps which solves this issue for them. Refer to the specific language provider documentation for more information on source maps as they are only used with certain languages and frameworks.

When dealing with minified JavaScript the information supplied in stack traces does not provide accurate line/column information to track down the source of the error. To deal with this you can utilize a source map which will provide the translation between the original JavaScript source and the minified version.


Raygun requires the following to complete the decoding process:

  • Payloads sent from a valid JS provider. This includes Raygun4JS and Raygun4Node (if enabled within the JS source map center).
  • Valid line/column numbers to be present in at least one line of the stack trace
  • An accessible minified JavaScript file as specified in the stack trace. This is either downloaded or retrieved from the source map center to determine if there is map file present
  • The map file to be correctly indicated in the minified JavaScript file using a footer comment (i.e. //# sourceMappingURL=index.min.js.map). Note: See the instructions below for how to work around this if the footer comment is not generated during your build.
  • An accessible source map file (either publicly hosted or uploaded to the source map center)
  • To provide inline code snippets we also require the sources content field of the map file to be present or for the map file to point to publicly accessible unminified source JavaScript files. If neither of these are provided decoding of line numbers and variable names can still succeed but no inline code will be displayed with the stack trace

note: Sourcemaps do not support custom providers names. To use sourcemaps with a custom provider, you will need to specify an appropriate client name matching raygun4js (raygun-js) or raygun4node (raygun-node). See the API reference here.


We recommend using UglifyJS2 to generate a source map file.

Both the minified JS and its map file should use relative pathing. Look into the -p and --source-map-root options.


If you do not wish to have publicly accessible JavaScript files you can upload them directly to Raygun from the JS Source Map Center. This is within the Application Settings submenu on the main dashboard.

Within the Source Map Center you can upload files and label them with the URL they would normally be accessed from. When a JavaScript error is mapped we will use the files you uploaded instead of trying to access them from your servers.

In addition to the upload page we offer an API endpoint, the URL is displayed in the Source Map Center and is specific to each application.

The endpoint expects form data with the following fields:

file – the JS file to be uploaded.

url – the url the file will be mapped to.

The request must be authenticated by a user who has access to an application. Either by adding either a basic auth header using an email/password, or an External Access Token, generated on the user's settings page, which is appended as a querystring parameter (eg. "https://app.raygun.com/upload/jssymbols/MyAppId?authToken=MyExternalAuthToken").

Screen shot of user settings page, generate external access token section is highlighted.

We recommend creating another Raygun user with a generic email e.g. external.api@mycompany.com. Then use either the basic auth or a new external token from this user's settings as a means of authentication.

note: It may take up to 2 hours for your sourcemaps to be processed and your errors to start mapping correctly.

Here is a cURL example request using Basic Authorization:

curl -L
  -X POST
  -u email@example.com:password
  -F "url=http://example.com/myjs.min.js"
  -F "file=@C:\website\js\myjs.min.js"  
  https://app.raygun.com/upload/jssymbols/MyAppId

Here is an example using the Grunt plugin grunt_http_upload using an External Access Token:

http_upload: {
  your_target: {
    options: {
      url: 'https://app.raygun.com/upload/jssymbols/MyAppId?authToken=MyExternalAuthToken',
      method: 'POST',
      data: {
        url: 'http://example.com/myjs.min.js'
      }
    },
    src: 'C:\website\js\myjs.min.js',
    dest: 'file'
  }
}

Here is an example using PowerShell:

$multipartContent = [System.Net.Http.MultipartFormDataContent]::new()
$stringHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$stringHeader.Name = "url"
$StringContent = [System.Net.Http.StringContent]::new("https://test.raygun.io/scripts/test.min.js.map")
$StringContent.Headers.ContentDisposition = $stringHeader
$multipartContent.Add($stringContent)

$multipartFile = 'test.min.js.map'
$FileStream = [System.IO.FileStream]::new($multipartFile, [System.IO.FileMode]::Open)
$fileHeader = [System.Net.Http.Headers.ContentDispositionHeaderValue]::new("form-data")
$fileHeader.Name = "file"
$fileHeader.FileName = "test.min.js.map"
$fileContent = [System.Net.Http.StreamContent]::new($FileStream)
$fileContent.Headers.ContentDisposition = $fileHeader
$multipartContent.Add($fileContent)

$body = $multipartContent

$response = Invoke-RestMethod 'http://app.raygun.com/upload/jssymbols/appIdentifier?authToken=XXX' -Method 'POST' -Headers $headers -Body $body
$response | ConvertTo-Json

To get started you will need a tool which can help produce a source map as part of producing a minified version of your JavaScript. We personally use UglifyJS and find it to be a great tool. To install it you will need Node.js installed, you can then run:

npm install uglify-js -g

This will install Uglify so that it's globally available which is what you will typically want.

To produce minified JavaScript we can simply run

uglifyjs example.js -o example.min.js

To produce minified JavaScript with a mapping file we can run

uglifyjs example.js -o example.min.js --source-map example.min.js.map

This produces the minified file "example.min.js" as well as a source map file "example.min.js.map"

If you deploy the minified file example.min.js to production but do not wish for any or some of these files to be publicly accessible you will need to upload these files to Raygun to get source mapped stacktraces.

You can do this from within Raygun by accessing the JS Source Map Center in the Application Settings sub menu.

Screenshot of the JS Source Center in the Raygun application sidebar menu.

Here you can simply select the minified, mapping and source files to upload. After uploading you can type the URL the resource is mapped to so when our source mapping process tries to retrieve the file, it uses the file you uploaded instead.

You can determine the URL to enter by looking at the map file's "file" and "sources" properties. You can then prepend the URL of the minified file on production minus the filename.

For instance, if we have a minified file example.min.js located at http://example.com/scripts/example.min.js and we upload example.min.js, example.js and example.min.js.map to Raygun. We would assign their URLs like this:

Screenshot of the sourcemap center user interface.

After the files are uploaded they will be used in the source mapping processes. This is what your mapped stacktrace will look like:

Screenshot of the output of a mapped stacktrace which has been derived from the source map provided.


Raygun allows you to configure an authentication key header for source map asset requests. The purpose of the header is to allow Raygun to request your privately hosted files whilst protecting them from unwanted access by adding a check to your server.

Setting up the authentication key header:

The authentication key is configured in your source maps settings in the source map centre.

Screenshot showing the "This Application's JavaScript Source Map Settings" box in the Js Source Map Centre with the header configuration highlighted.

Here is an example of how the header can be used, using node.js:

router.get('/scripts/:fileName.map', (req, res, next) => {
if (req.header('Raygun-SourceMap-Auth') === SourceMapCenterAuthKey) {
const mapPath = path.join(__dirname, `/scripts/${req.params.fileName}.map`);

    res.sendFile(mapPath, {}, err => {
    console.error(err);
    next(err);
    });
}
else {
res.sendStatus(404);
}
});

With many mobile applications being written in JavaScript within containers such as Apache Cordova, using Raygun4js is an appealing way to track errors across all platforms. However, as the application is hosted on the phone instead of a website with a static URL you may find that error stacktraces contain files paths which differ across different platforms and devices. This introduces some difficulty when trying to utilize source maps which require the minified and mapping files to be uploaded and labeled with exactly the same URLs as would appear in a stacktrace.

For this reason we recommend adding a handler to the raygun4js provider to rewrite file's URLs before the error is reported back to Raygun. This means that errors will be reported from the same domains and not unique domains for every platform or device.

An example of such a handler is shown below:

//handler method
var beforeSend = function(payload) {
  var stacktrace = payload.Details.Error.StackTrace;

  var normalizeFilename = function(filename) {
      var indexOfJsRoot = filename.indexOf("js");
      return 'http://normalizedurl.com/' + filename.substring(indexOfJsRoot);
  }

  for(var i = 0 ; i < stacktrace.length; i++) {
      var stackline = stacktrace[i];
      stackline.FileName = normalizeFilename(stackline.FileName);
  }
  return payload;
}

//attaching the handler to the Raygun provider
Raygun.onBeforeSend(beforeSend);

This handler removes the platform and device specific paths from the URLs present in an error's stacktrace.

For instance an error occuring on an Android phone within the file

file://android_asset/www/js/myjsfile.min.js

and on an iOS device within the file

file://accounts/1234/appdata/b12b33f1-519b-4d1c-8d68-315513ecbac1/www/js/myjsfile.min.js

will both report

http://normalizedurl.com/js/myjsfile.min.js

as the URL of the file within which the error occurred.

This allows the use of a single set of sourcemaps for source mapping across all deployments.

Notes:

There could be up to a 2 hour delay before the mapping process starts utilizing any uploaded files. To reprocess any errors which occur during this time simply hit the "Re-process this error for Source Maps" button on an error instance.

Code snippet insertion is only available if there are less than 50 source files referenced in the map file.


Raygun supports source mapping for Node.js stacktraces which include column numbers. To enable this feature simply upload your map files as per the instructions on this page and enable the processing of Node.js errors with this setting in Raygun.

Node.js option for source maps


Files in the JavaScript Source Map Center can be managed via a few API calls.

A GET request to https://app.raygun.com/jssymbols/[applicationIdentifier] will return a JSON object listing all files within the center. eg.

curl -L
  -X GET
  -u my@email.com:mypassword
  https://app.raygun.com/jssymbols/[applicationIdentifier]

Returns:

{
  "Count": totalNumberOfItems,
  "Items": [
    {  
       "Url": "https://urlOfItem",
       "FileName": "fileName.js",
       "UploadedOn": "2016-01-01..."
    },
    ...
  ]
}

A DELETE request to https://app.raygun.com/jssymbols/[applicationIdentifier]/all will remove all files within the center. eg.

curl -L
  -X DELETE
  -u my@email.com:mypassword
  https://app.raygun.com/jssymbols/[applicationIdentifier]/all

A DELETE request to https://app.raygun.com/jssymbols/[applicationIdentifier] will remove files with the specified URLS from the center. eg.

curl -L
  -X DELETE
  -u my@email.com:mypassword
  -F "url=https://example.com/js/myjs.min.map"
  https://app.raygun.com/jssymbols/[applicationIdentifier]

All requests use the same authentication methods as the upload call (Basic Authentication and Token Authentication).


If your generated minified file does not include the //# sourceMappingURL=... pragma at the end of the script, you can upload the .map file to the Source Map Center and set the URL to be the original minified source file URL.

  • Source file: http://example.com/dist/index.min.js
  • Map file: http://example.com/src/index.min.js.map
  1. Upload the map file
  2. Set the URL field to be the source file URL

Screenshot showing the source map center with the map file uploaded and the URL field set to the source file URL.


If source mapping fails, you should see one or both of the sections below. If you don't see these sections, try clicking "Re-process this error for Source Maps":

Screenshot showing both "these minified files could not be obtained" and "Source map comments were not detected in the following minified files" messages

The "minified files could not be obtained" section lists the files we were unable to locate after checking both the URL and the JS Source Map Center. Please make sure that either:

  • The file is accessible at the given URL
  • The file has been uploaded to the JS Source Map Center, with the URL field exactly matching what we display in the stack trace.

If the listed file is not a web address (e.g the first file in the screenshot above), just enter whatever is displayed (a file path in this case) into the "URL" field in the JS Source Map Center for that file e.g: Screenshot showing the source map centre with two entries, the URLs are https://myapp.com/bundles/app.min.abcd1234.js and usr/src/myapp/api/dist/src/example-file.js

If you've checked that the JS Source Map Center URLs match the list of unobtained files in the stack trace, and source mapping still doesn't work, please reach out to our engineering support team via the contact page, or click "Contact Raygun" in the app.