Troubleshooting
If you need help solving issues with your Sentry JavaScript SDK integration, you can read the edge cases documented here. If you need additional help, you can view our forums, and customers on a paid plan may also contact support.
Debugging Additional Data
You can view the JSON payload of an event to see how Sentry stores additional data in the event. The shape of the data may not exactly match the description.
For more details, see the full documentation on Event Payload.
Max JSON Payload Size
maxValueLength
has a default value of 250, but you can adjust this value according to your needs if your messages are longer. Please note that not every single value is affected by this option.
CORS Attributes and Headers
To gain visibility into a JavaScript exception thrown from scripts originating from different origins, do two things:
- Add a crossorigin=”anonymous” script attribute
<script src="http://another-domain.com/app.js" crossorigin="anonymous"></script>
The script attribute tells the browser to fetch the target file “anonymously.” Potentially user-identifying information like cookies or HTTP credentials won’t be transmitted by the browser to the server when requesting this file.
- Add a Cross-Origin HTTP header
Access-Control-Allow-Origin: *
Cross-Origin Resource Sharing (CORS) is a set of APIs (mostly HTTP headers) that dictate how files ought to be downloaded and served across origins.
By setting Access-Control-Allow-Origin: *
, the server is indicating to browsers that any origin can fetch this file. Alternatively, you can restrict it to a known origin you control:
Access-Control-Allow-Origin: https://www.example.com
Most community CDNs properly set an Access-Control-Allow-Origin
header.
$ curl --head https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.js | \
grep -i "access-control-allow-origin"
Access-Control-Allow-Origin: *
Unexpected OPTIONS request
If your application started to misbehave because of performing additional OPTIONS requests, it is most likely an issue with unwanted sentry-trace
request headers, which can happen when you are using too generic a configuration for our Tracing Integration in the Browser SDK.
To fix this, change the tracingOrigins
option during SDK initialization. For more details, see Automatic Instrumentation in our Performance Monitoring documentation.
instrument.js
Line Numbers for Console Log statements
If instrument.js
displays in your console while debugging, add Sentry to your framework blackboxing settings like: /@sentry/
so Chrome ignores the SDK stackframes when debugging.
Dealing with Ad-Blockers
When you are using our CDN, ad-blocking or script-blocking extensions may prevent our SDK from being fetched and initialized properly. Because of this, any call to the SDKs API will fail and may cause your application to behave unexpectedly.
Additionally, even when the SDK is downloaded and initialized correctly, Sentry endpoints that need to receive captured data may be blocked as well. This prevents any error reports, sessions health, or performance data from being delivered, making it effectively unavailable in sentry.io.
You can work around the first issue in multiple ways explained above. However, the endpoint blockage can be only resolved using the tunnel.
Using the tunnel
Option
A tunnel is an HTTP endpoint that acts as a proxy between Sentry and your application. Because you control this server, there is no risk of any requests sent to it being blocked. When the endpoint lives under the same origin (although it does not have to in order for the tunnel to work), the browser will not treat any requests to the endpoint as a third-party request. As a result, these requests will have different security measures applied which, by default, don't trigger ad-blockers. A quick summary of the flow can be found below.
Starting with version 6.7.0
of the JavaScript SDK, you can use the tunnel
option to tell the SDK to deliver events to the configured URL, instead of using the DSN. This allows the SDK to remove sentry_key
from the query parameters, which is one of the main reasons ad-blockers prevent sending events in the first place. This option also stops the SDK from sending preflight requests, which was one of the requirements that necessitated sending the sentry_key
in the query parameters.
To enable the tunnel
option, provide either a relative or an absolute URL in your Sentry.init
call. When you use a relative URL, it's relative to the current origin, and this is the form that we recommend. Using a relative URL will not trigger a preflight CORS request, so no events will be blocked, because the ad-blocker will not treat these events as third-party requests.
Sentry.init({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
tunnel: "/tunnel",
});
Once configured, all events will be sent to the /tunnel
endpoint. This solution, however, requires an additional configuration on the server, as the events now need to be parsed and redirected to Sentry. Here's an example for your server component:
<?php
// Change $host appropriately if you run your own Sentry instance.
$host = "sentry.io";
// Set $known_project_ids to an array with your Sentry project IDs which you
// want to accept through this proxy.
$known_project_ids = array( );
$envelope = stream_get_contents(STDIN);
$pieces = explode("\n", $envelope, 2);
$header = json_decode($pieces[0], true);
if (isset($header["dsn"])) {
$dsn = parse_url($header["dsn"]);
$project_id = intval(trim($dsn["path"], "/"));
if (in_array($project_id, $known_project_ids)) {
$options = array(
'http' => array(
'header' => "Content-type: application/x-sentry-envelope\r\n",
'method' => 'POST',
'content' => $envelope
)
);
echo file_get_contents(
"https://$host/api/$project_id/envelope/",
false,
stream_context_create($options));
}
}
Check out our examples repository to learn more about it.
If your use-case is related to the SDK package itself being blocked, any of the following solutions will help you resolve this issue.
Using Package Directly
The best way to deal with script-blocking extensions is to use the SDK package directly through the npm
and bundle it with your application. This way, you can be sure that the code will be always be there as you expect it to be.
The second way is to download the SDK from our CDN and host it yourself. This way, the SDK will still be separated from the rest of your code, but you'll be certain that it won't be blocked since its origin will be the same as the origin of your website.
You can easily fetch it using curl
or any other similar tool:
curl https://browser.sentry-cdn.com/5.20.1/bundle.min.js -o sentry.browser.5.20.1.min.js -s
Using the JavaScript Proxy API
The last option is to use Proxy
guard, which will make sure that your code won't break, even when you call our SDK, which was blocked. Proxy
is supported by all browser except Internet Explorer, though there are no extensions in this browser. Also if Proxy
is not in any of your user's browser, it will be silently skipped, so you don't have to worry about it breaking anything.
Place this snippet immediately above the <script>
tag containing our CDN bundle. The snippet in a readable format presents like this:
if ("Proxy" in window) {
var handler = {
get: function(_, key) {
return new Proxy(function(cb) {
if (key === "flush" || key === "close") return Promise.resolve();
if (typeof cb === "function") return cb(window.Sentry);
return window.Sentry;
}, handler);
},
};
window.Sentry = new Proxy({}, handler);
}
If you would like to copy and paste the snippet directly, here it is minified:
<script>
if ("Proxy" in window) {
var n = {
get: function(o, e) {
return new Proxy(function(n) {
return "flush" === e || "close" === e
? Promise.resolve()
: "function" == typeof n
? n(window.Sentry)
: window.Sentry;
}, n);
},
};
window.Sentry = new Proxy({}, n);
}
</script>
Using a Client directly
To be able to manage several Sentry instances without any conflicts between them you need to create your own Client
.
This also helps to prevent tracking of any parent application errors in case your application is integrated
inside of it. In this example we use @sentry/browser
but it's also applicable to @sentry/node
.
import { BrowserClient } from "@sentry/browser";
const client = new BrowserClient({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
});
client.captureException(new Error("example"));
While the above sample should work perfectly fine, some methods like configureScope
and withScope
are missing on the Client
because the Hub
takes care of the state management. That's why it may be easier to create a new Hub
and bind your Client
to it. The result is the same but you will also get state management with it.
import { BrowserClient, Hub } from "@sentry/browser";
const client = new BrowserClient({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
});
const hub = new Hub(client);
hub.configureScope(function(scope) {
scope.setTag("a", "b");
});
hub.addBreadcrumb({ message: "crumb 1" });
hub.captureMessage("test");
try {
a = b;
} catch (e) {
hub.captureException(e);
}
hub.withScope(function(scope) {
hub.addBreadcrumb({ message: "crumb 2" });
hub.captureMessage("test2");
});
Dealing with integrations
Integrations are setup on the Client
, if you need to deal with multiple clients and hubs you have to make sure to also do the integration handling correctly.
Here is a working example of how to use multiple clients with multiple hubs running global integrations.
import * as Sentry from "@sentry/browser";
// Very happy integration that'll prepend and append very happy stick figure to the message
class HappyIntegration {
constructor() {
this.name = "HappyIntegration";
}
setupOnce() {
Sentry.addGlobalEventProcessor(event => {
const self = Sentry.getCurrentHub().getIntegration(HappyIntegration);
// Run the integration ONLY when it was installed on the current Hub
if (self) {
event.message = `\\o/ ${event.message} \\o/`;
}
return event;
});
}
}
HappyIntegration.id = "HappyIntegration";
const client1 = new Sentry.BrowserClient({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0",
integrations: [...Sentry.defaultIntegrations, new HappyIntegration()],
beforeSend(event) {
console.log("client 1", event);
return null; // Returning null does not send the event
},
});
const hub1 = new Sentry.Hub(client1);
const client2 = new Sentry.BrowserClient({
dsn: "https://examplePublicKey@o0.ingest.sentry.io/0", // Can be a different DSN
integrations: [...Sentry.defaultIntegrations, new HappyIntegration()],
beforeSend(event) {
console.log("client 2", event);
return null; // Returning null does not send the event
},
});
const hub2 = new Sentry.Hub(client2);
hub1.run(currentHub => {
// The hub.run method makes sure that Sentry.getCurrentHub() returns this hub during the callback
currentHub.captureMessage("a");
currentHub.configureScope(function(scope) {
scope.setTag("a", "b");
});
});
hub2.run(currentHub => {
// The hub.run method makes sure that Sentry.getCurrentHub() returns this hub during the callback
currentHub.captureMessage("x");
currentHub.configureScope(function(scope) {
scope.setTag("c", "d");
});
});
Third Party Promise Libraries
When you include and configure Sentry, our JavaScript SDK automatically attaches global handlers to capture uncaught exceptions and unhandled promise rejections. You can disable this default behavior by changing the onunhandledrejection
option to false
in your GlobalHandlers integration and manually hook into each event handler, then call Sentry.captureException
or Sentry.captureMessage
directly.
You may also need to manage your configuration if you are using a third-party library to implement promises. Also, remember that browsers often implement security measures that can block error reporting when serving script files from different origins.
Events With "Non-Error Exception"
If you’re seeing errors with the message “Non-Error exception (or promise rejection) captured with keys: x, y, z.”, this happens when you a) call Sentry.captureException()
with a plain object, b) throw a plain object, or c) reject a promise with a plain object.
You can see the contents of the non-Error object in question in the __serialized__
entry of the “Additional Data” section.
To get better insight into these error events, we recommend finding where the plain object is being passed or thrown to Sentry based on the contents of the __serialized__
data, and then turning the plain object into an Error object.
- Package:
- npm:@sentry/gatsby
- Version:
- 8.24.0
- Repository:
- https://github.com/getsentry/sentry-javascript