Debugging: Slow Network Requests and "Cannot read property 'id' of undefined"
We understand the value of JavaScript error monitoring here at TrackJS. Consequently, we run TrackJS on all of our own web properties to log our JS errors. We’re dilligent about fixing errors as they happen, and most issues are caught in development environments, or immediately in production. However, sometimes we’ll get a sporadic error that’s hard to pin down. This is an example of how we use our own product to debug a thorny problem.
There Are Always Errors, But Are They Problematic?
The first step is determining whether you even care about an error. JavaScript errors can be noisy, and we give you great tools to ignore them if you want.
Here’s a screenshot of the rollup page in TrackJS for the error. We can see it occurs sporadically, and has only affected 6 of our users in the last 30 days. I like to start at this page when debugging to get a sense for the impact and severity of a problem.
While the number of users impacted is not high, the error is impacting the /account
portion of the site. This is where users can change important customer information, or update their payment/billing. We really want this to work reliably!
This error is worth fixing (as opposed to ignoring with an Ignore Rule), the next step is diving in to the details.
The Error Details
The first thing I notice in this case is the stack trace. It’s from an older part of our JavaScript code. I can tell because there’s no sourcemap generated (we use backbone.js with no transpilation step - gasp - for some parts of the site still). Fortunately, we don’t need fancy tricks. The stack frames, coupled with our penchant for long descriptive function names, means I know exactly which file this code is in.
The error is coming from our checkout/billing/subscription JavaScript. This code is responsible for interfacing with Stripe, handling payments and billing updates, and making sure customers can subscribe. This is mission critical code!
The Plot Thickens
But something doesn’t make sense. We only load the JavaScript in question on the /account
/subscription
page. From the Telemetry Timeline I can see the error occurred on the /account
/team
page, only about half a second after we navigated.
And anyways, we were coming from the /shared/errors
page, not anything subscription related. This code should never be running! But sure enough I can see from the timeline that Stripe is getting loaded, right after the user navigated to /shared/errors
. You can see they clicked the link, we made a PJAX request, the URL changed via pushState
and then the Stripe code loads.
I double checked the server template for /shared/errors
to make sure there’s no Stripe or billing related code. There isn’t. But… when a potential customer’s trial ends, we redirect (almost) every path to the subscription page. The user can still navigate to the /account
section and make changes, but instead of seeing their data they see a subscribe page for other routes. This could explain why the code is running on weird URLs. But why is it breaking?
The Network Ain’t Reliable
We don’t want to load all the Stripe JavaScript unless we have to. So we lazy load their checkout.js
file only if the user is on the subscription page. However, networks can be slow. In the event that the user clicks fast enough, and the checkout.js
file is slow to load, we’ll attempt to initialize the rest of the JavaScript on the wrong page!
Reproducing the Problem Is Easy Now
Once I realized that all kinds of URL paths could be serving the subscription JavaScript, but only to trial users, it made sense why this error was so sporadic. Further, the only way make it happen is to navigate quickly from one page to the next (on a somewhat congested network). Since we use PJAX, all JavaScript stays resident in memory even across page transitions, and our lazy loading of the Stripe checkout JavaScript created a perfect storm.
I was quickly able to reproduce the problem by creating an expiring trial account. The big concern I had was whether this error was impacting billing actions. I was fortunately able to confirm that it was not. Without being able to reproduce the problem, there’s no way to know for sure though! Since the severity of this error is low, we’ll triage it to figure out whether it’s worth adding a defensive check, or better just to ignore it as there is no user impact.
Summary
Cannot read property 'Id' of undefined
errors happen because the code is executing in an unexpected context. In our case, it’s because the user switched pages quickly, which is pretty likely to happen for highly-interactive applications like TrackJS. Unexpected things happen in production!
TrackJS gives you a lot more tools to figure out what’s happening than I covered today. Please sign up for a free trial and give it a try!