import facepalm;
Nicholas Cloud
Posted on March 11, 2020
This article was originally published at nicholascloud.com.
Sometimes bugs can be particularly evasive, and today I had such a one.
A module in deep in our codebase was throwing an Error
, but only in Mozilla's Firefox browser.
The error was NS_ERROR_ILLEGAL_VALUE
.
I did some quick DuckDuckGoing and found that the error occurs when a native DOM function in Firefox is passed a value of a type it does not expect.
The stack trace led back to this line in our application code:
const hit = find( cache, c => c.original === obj );
if ( hit ) {
return hit.copy;
}
// ...some time later...
return someUncachedObject;
"@-E$!&&@#", I thought. "Why is lodash's find()
function passing a bad value to a native function?"
You see, I use lodash
all the time. So much, in fact, that I made one fatal error in my diagnosis.
I assumed that because the find()
function was defined, that lodash
had indeed been imported.
How. Wrong. I. Was.
It turns out that window.find()
is, in fact, a non-standard, but nevertheless nearly omnipresent function that is designed to search a DOM document for a particular string. And since any function attached to window
is global, a missing import of the same name -- say, a missing lodash/find
import -- would not raise any alarms. The code built. The code ran. And it ran without error in every browser but Firefox. Why?
The window.find()
function expects a first argument of type String
. In modern browsers other than Firefox (pretty much all the Chromium-based browsers), passing a non-String
argument to window.find()
will simply cause the function to return false
. As you can see in the snippet above, though rendering the cache useless, the application nevertheless continued to work. In Firefox
, however, window.find()
will throw if its first argument is not of type String
. Thus my bug.
I am ashamed to say how long it took me to realize lodash/find
was not the function being called.
In the end I applied the great wisdom of Spock's ancestors, and started considering things that could not possibly be the case, until it dawned on me that perhaps -- just perhaps -- find()
was not what it appeared to be after all.
And a single import find from "lodash/find";
statement fixed the bug.
Posted on March 11, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.