Originally posted on my Medium blog »
Photo by Graham Ruttan on Unsplash.
Recently, a few customers ran into a problem in an Angular web application where an exception was thrown. Because of this problem, you couldn’t use a major part of the application. As a developer, I want to have clear instructions on how to reproduce an issue to not waste time. Good customer support or customers willing to share more details beyond “It isn’t working for me” can provide meaningful information to make the life of developers easier. Customer support wasn’t able to reproduce the issue on their devices, yet it was consistently happening for a few customers.
When this issue was brought up, I did what I typically do when encountering issues like this. This article is about this particular problem as well as debugging critical issues.
Finding the Root Cause
I used Instana, which is a great SaaS for monitoring microservices and websites. Through our monitoring tool, I was able to confirm that the error occurred for a few customers as well as the user actions that led to the issue. Even with this information, I couldn’t reproduce the issue at first.
I had the error stack trace thanks to our monitoring tool. With this, I found the code that caused the exception to be thrown. As you can see below, this code is querying all stylesheets in the DOM and doing something with the CSS rules of each stylesheet.
Uncaught DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
Our monitoring tool also provides browser data, so I checked which browsers were affected the most. It turned out it’s mainly recent versions of Chromium-based browsers like Google Chrome. As many of my coworkers use Google Chrome as the main browser for development, I found it strange that no other developer stumbled upon this yet.
There were no tests for this function. I tried to replicate the issue with unit tests with Jest, but the tests ran through successfully.
I searched online for this particular error message and found some helpful posts regarding rather recent changes in Chrome. In the latest version of Chrome, CORS security rules are also applicable for stylesheets (similar to Iframe rules). You can load and render them, but you cannot access the content stylesheets loaded from another domain through JavaScript. While this information was helpful, I still did not understand why this should be a problem.
How to Fix the Error
With all the knowledge mentioned above, a theory formed in my head: What if somehow there were stylesheets loaded into the DOM that were not from us? This was the only thing I could think of that could cause this issue, so I began thinking, “How do stylesheets not from us get loaded into the DOM?”
The answer: browser extensions. You probably know web extensions that remove ads from websites or provide functionality that your browser does not have. Browser extensions are typically built on web technologies like HTML, CSS, and JavaScript. This means it’s totally possible for a web extension to load a stylesheet from another domain — unless you are not using extensions that do that.
The issue can be reproduced easily by injecting a style (e.g. by using the Chrome Developer Tools) that points to a CSS file from another domain (e.g. a CDN). If your CSS Stylesheet is from the same domain as the HTML, you will be able to access the document.styleSheets.get(index).cssRules property. Otherwise, it will throw the following error:
Uncaught DOMException: Failed to read the 'cssRules' property from 'CSSStyleSheet': Cannot access rules
Now that we understand and found the root cause, the fix for the problem is easy: only keep stylesheets that are loaded from the same domain or where href is null (this may be the case if stylesheets are inlined, such as when using Angular):
After the fix was released, we reached out to affected customers and they could confirm the issue was not occurring anymore. Besides, our monitoring tool also did not report any more occurrences of this issue, so we knew we were on the safe side.
Conclusion
Thanks for reading this short article. As you can see, the fix for the issue can be implemented in minutes, but understanding the root cause of issues often takes longer than we expect.
Did this help you? Let me know in the comments.
Top comments (0)