lazysizes: TypeError: Illegal invocation at HTMLDocument.document.createEvent only on iOS Safari mobile

Hi everyone,

I just deployed lazysizes in production for the first time. It is working great, except that my error reporting tool (rollbar dot io), reports a lot of errors only on mobile Safari 10 & 11. Unfortunately I cannot reproduce it on my end.

The stacktrace I get is (I re deployed using the unminified script to know where it comes from) :

TypeError: Illegal invocation
File "(unknown)" line 1 col 35801 in HTMLDocument.document.createEvent
File https://www.fishfriender.com/public/lazysizes/lazysizes.js line 71 col 24 in triggerEvent
File https://www.fishfriender.com/public/lazysizes/lazysizes.js line 526 col 13 in unveilElement
File https://www.fishfriender.com/public/lazysizes/lazysizes.js line 393 col 7 in checkElements
File https://www.fishfriender.com/public/lazysizes/lazysizes.js line 171 col 4 in run

Script is included like this : <script src="/public/lazysizes/lazysizes.js" async=""></script>

Does it speak to anyone ?

About this issue

  • Original URL
  • State: open
  • Created 6 years ago
  • Reactions: 30
  • Comments: 44 (7 by maintainers)

Commits related to this issue

Most upvoted comments

We did the same thing. It seems as if the FB crawlers execute javascript. We’ve had other libraries reporting errors that weren’t really errors. Will do some more investigating.

Thank you all for your information. I will look into this this weekend. 'As you know it is hard to fix a bug without being able to reproduce it…

I’ll do my best.

Not sure how much this will help, but from investigating similar issues in the past - I’ve found that most of the libraries that are being mentioned here, especially tracking users interactions and errors (such as Sentry, BugSnag, trackjs) will shim native methods, which can actually cause problems.

For instance, Bugsnag shims setTimeout, setInterval, document.addEventListener and document.removeEventListener, which can actually break functionality. I would not be surprised either if somewhere along the line Facebook’s tracking scripts are doing something similar.

From what I’ve read previously when the shimming takes place, any events that managed to get registered before the shimming takes place, get dropped, causing problems.

It would be worth testing these instances without the bug tracking software being used on a native device and seeing if the errors still occur via remote / USB debugging.

Just wanted to drop in and share my appreciation for all of you guys investing time in trying to solve this issue, and especially @alepee - who opened a PR (to no avail, but still - we now know CustomEvent doesn’t fix it).

I have this issue in my sites too, and it bothered me for some time (I also use Sentry, and get many alerts). Reading this thread convinced me to just let this go, and ignore these errors. Hopefully with time they’ll just stop happening (Maybe Apple fixes them on their side, maybe some refactor in lazysizes somehow make them goes away).

So thanks.

Ok, I think I can confirm that it’s Facebook’s doing.

  • All the IPs that error events come from are Facebook’s
  • Every single one of them has the fbclid get param in the URL.

Whatever it is, it at least seems to run all JS code properly and doesn’t omit any script objects like in some other weird cases. Also the error object has a prop that is basically a copy of the Window object, except all its props are undefined.

I’m also going to take a look at our server logs to clarify if the requests that correspond to these ones have additional attributes that could hint at Facebook. We’re also pretty much inclined to block the heck out of it at least in Sentry, but maybe even server-side since lasysizes is by far not the only lib that triggers that.

Yet before that I’m eager to give the changed version a shot to see if it fixes the problem. We have a shit ton of events under this error, so I believe we’ll be able to tell right away. Thanks for all your efforts here, will keep you updated.

Bugsnag reports the same. Haven’t looked into it yet as it’s rather an uncommon issue, but yes, I’m experiencing it also.

This should go somewhere in a global knowledge base for everyone to see. Thank you for the thread!

For us the issue is mostly from iOS users, in almost all such cases the browser is reported as Mobile Safari. Still about 15% of the errors are coming from Chrome, including on Windows. In all the instances Sentry points at this line of code as the source. Here is the full stack trace:

TypeError: Illegal invocation
  at HTMLDocument.document.createEvent(:519:5)
  at triggerEvent(./node_modules/lazysizes/lazysizes.js:71:1)
  at unveilElement(./node_modules/lazysizes/lazysizes.js:543:1)
  at fn(./node_modules/lazysizes/lazysizes.js:401:1)
  at B(./node_modules/lazysizes/lazysizes.js:176:1)

Gave 4.1.4 a whirl and we’re still seeing the error in JS. Oddly, we’ve noticed that all the offending errors originate from Facebook IP’s. We’re wondering if there’s some cut down browser trying to load the pages which explains why it’s incredibly difficult to replicate but seemingly so “common” in our Bugsnag report 🤷‍♂️

F#ck ::face:b00c

@if (str_ends_with(request()->getClientIp(), '::face:b00c') === false)
    <script type="text/javascript">
        window.bugsnagClient = bugsnag({
            apiKey: '{{ $key }}',
            releaseStage: '{{ config('app.env') }}'
        });
    </script>
@endif```

Why not use CustomEvent ?

var triggerEvent = function(elem, name, detail, noBubbles, noCancelable) {
	if (typeof window.CustomEvent !== 'function') {
		function CustomEvent(event, params) {
			params = params || {
				bubbles: false,
				cancelable: false,
				detail: null,
			};
			var evt = document.createEvent('CustomEvent');
			evt.initCustomEvent(
				event,
				params.bubbles,
				params.cancelable,
				params.detail
			);
			return evt;
		}
		CustomEvent.prototype = window.Event.prototype;
	}

	if (!detail) {
		detail = {};
	}

	detail.instance = lazysizes;

	var event = new CustomEvent(name, {
		bubbles: !noBubbles,
		cancelable: !noCancelable,
		detail: detail,
	});

	elem.dispatchEvent(event);
	return event;
};

I thought I’d add my findings to this. We’re getting the same error showing up in Bugsnag. I’ve tried replicating this issue by hitting up the offending link with a fbclid using BrowserStack (Mobile Safari 13). Unfortunately this does not accurately replicate the error. We use FullStory for analytics, which means I’m able to track down and rewatch sessions where this error has occurred in Bugsnag.

I was concerned this error was causing issues for users, as the session recording drops off straight after page load which is unexpected. I noticed the same behaviour when I reviewed the recordings of my own sessions where I’d tried to replicate this bug. FullStory stops recording the session, however I’m still able to interact with the site and there are no user issues.

My next step would be to log into a Facebook account on a phone using Safari 13, then click on one of the links causing this bug, however BrowserStack is quite locked down with apps and I don’t have a suitable device to test this at the moment. Has anyone tried to replicate this bug by clicking a link directly from the Facebook app?

@ictgtvt nice finding.

I can guess it some Facebook bot to detect frauds\malware and stuff like this, probably they want to know you didnt changed the content too much after sharing it or I dont know what

@alepee Yes, the current API I’m using is an old one, but you can say for sure that it will stay no one will remove it. The web is built upon backwards compatibility. Additionally your code does code branching which results in the situation that some browsers execute the code and others not. This often results in mistakes, harder testing and is a maintainability hazard.

In fact your code demonstrates this very good because - although I haven’t run it in a browser - I see some mistakes. (see also: dom4)

Yes, same here. Clearly, an error tracked by trackjs.com on our production site:

v = function(a, d, e, f, g) { var h = b.createEvent("CustomEvent"); return e || (e = {}), e.instance = c, h.initCustomEvent(d, !f, !g, e), a.dispatchEvent( h), h

This can’t work as b. is not provided in function(…) call