A reader contacted me this weekend to inform me that jQuery 1.6.2 had broken all of my old examples of using jQuery with ASP.NET services. Not good! How could such a simple update have caused this?!

I didn’t really expect that updating from jQuery 1.6.1 to 1.6.2 would break anything, much less break everything.

As it turns out, the problem didn’t have anything to do with jQuery 1.6.2 or my own code. However, while investigating, I ended up falling prey to the same treachery that led to the original bug report.

This is why we can’t have nice things

Google has been raked across the coals this year, with serious questions being raised about their ability to handle the mounting problems of hyper-SEO’d spam sites and content farms. Unfortunately, this weekend’s problem with jQuery 1.6.2 was yet another failure in Google’s ongoing struggle with that dross.

Hopefully, the situation will have improved by the time you’re reading this post, but as I’m writing this, the first organic search result for jQuery 1.6.2 is this one:

If you’re in a hurry to download a copy of the latest jQuery revision, that result looks legitimate enough, but look closely at the domain name. Notice that it’s .it, not .com. This domain is not owned or controlled by the jQuery Project.

Regardless, following the link to this search result takes you to what appears to be an authentic jQuery blog post:

As legitimate as it looks, that site is an entirely unsanctioned ripoff of the official jQuery site. Yet, this impostor has somehow out-ranked the official jQuery blog in Google searches for its own content.

That’s lame, but what’s the harm?

In my hurry, I didn’t notice the .it domain, much less that this seemingly authentic jQuery blog post was an automated copy of the real thing. I right-clicked the link to unminified jQuery 1.6.2, saved it locally, and went about my testing.

After unwittingly downloading this fraud’s copy of jQuery 1.6.2 and testing it in some of my old samples, I did indeed begin seeing JavaScript errors as my reader had reported. Closer inspection revealed that the errors were related to the jQuery script include itself though, not my own code.

So, what was going on? Following the errors back to their source, I found this at the very end of the jQuery script I had downloaded:

Things were looking good until that final Time to generate bit at the very end. That is obviously not valid JavaScript. Likely, it was appended to the file by whatever tool was used to clone the official site.

When browsers hit a hard syntax error like this while parsing a script include, the entire script is ignored and no part of it makes its way into the DOM. So, this tiny error at the very end of thousands of lines of code was all it took to effectively disable the entire library.

Finding a legitimate copy of jQuery

So, where should you be looking for the authentic copies of jQuery 1.6.2?


Posting criticisms of Google on a site that depends on search for over 60% of its traffic may be asking for trouble, but this is a flagrant failure on Google’s part. Algorithms be damned; they simply cannot allow a random AdSense splog to hijack well-targeted searches for the most popular JavaScript library on the planet.

Imagine how much worse things could have been if this site were actively evil instead of harmlessly inept. Injecting even a tiny bit of malicious JavaScript into such a ubiquitous library could have resulted in a minor catastrophe, as thousands of developers downloaded that subverted version and tested it on their sites.

Update: Thanks to Pierre’s helpful comment below, the issue that allowed the scraper’s site to outrank the original is now apparent: requests to individual post permalinks on blog.jQuery.com return a 500 error when requested with a User-Agent of Googlebot.

As frustrating it is to see a splog outrank the original, there’s no way to fault Googlebot for not indexing something that it couldn’t see. My original conclusion about this being a failure on Google’s part was obviously unwarranted.

Sorry about that.

Epilogue: As of last night, this is what I’m seeing returned for jQuery 1.6.2 searches now.

All’s well that ends well.