What Happened to Operation Aborted?

Have you ever seen this dialog while surfing the web in Internet Explorer?

A screen shot of Internet Explorer 7 with a dialog superimposed with the text: Internet Explorer cannot open the Internet site. Operation aborted.

You browse to your favorite news site. The content starts loading, you've already started reading the headline, and then it happens. Those of you familiar with the operation aborted dialog know that it spells sudden doom for the website you're currently viewing. Unsuspecting users have no idea what it means and simply click 'OK' and then watch in horror as the web page they were just reading disappears; only to be replaced by an navigation error screen. More savvy users move the dialog out of the way so that they can finish reading what was visible before they too accept the inevitable...

This dialog (and its side-effects) is gone in Internet Explorer 8 Beta 1.

What caused the operation aborted error?

The operation aborted dialog in Internet Explorer 7 is triggered by an HTML parsing exception that occurs when all the following specific conditions are met:

  1. The HTML file is being parsed
  2. Script is executing
  3. The executing script attempts to add, or remove an element from an unclosed ancestor in the markup tree (not including the script block's immediate parent element).

You can see that each of these conditions is true in the following example markup:

<html>  <body>    <div>    <script type="text/javascript"> var newElem = document.createElement('foo');     document.body.appendChild(newElem);    </script>   </div> </body> </html>

The HTML file is being parsed, and encounters a script block. The script block contains inline script which creates a new element and attempts to add it to the BODY (document.body.appendChild(newElem)) element before the closing BODY tag has been encountered by the parser. Note that if I removed the highlighted DIV element, then this problem would not occur because the script block's immediate parent would be BODY, and the script block's immediate parent is immune to this problem.

Unfortunately the operation aborted dialog was always thrown at the top-level of a web page, even if the problem occured in an iframe. In fact, in most scenarios that we encountered, ad injection in an iframe was usually the root cause of this error. After the user dismissed the error dialog, Internet Explorer would navigate away from the page.

What we did in Internet Explorer 8 Beta 1

Screen shot of Internet Explorer 8, with emphasis given to the status bar where a script-error indicator is present

In Internet Explorer 8, our goal is to change the behavior that previously caused the following problems:

  • The operation aborted error was a modal dialog. The dialog was not actionable by any user.
  • Dismissing the operation aborted dialog caused Internet Explorer to navigate to an error page. This prevented any potential debugging of the affected page.

When the HTML parser throws the operation aborted exception, rather than announce this error to the world, Internet Explorer 8 Beta 1 discreetly tucks this information away into the list of script errors associated with the webpage and stops parsing HTML and running script at that point. We also tried to provide a little more help to those developers who encounter this error (but don't read the IE blog) by including the KB article number in the text that describes this problem:

HTML Parsing Error: Unable to modify the parent container element before the child element is closed (KB927917)

A simple web search for "KB927917" in major search engines will usually turn up the corresponding Knowledge Base article as the first hit. That article describes the specifics of this problem and available workarounds.

Interoperability observations and feedback request

It's intriguing to observe the parsing behavior of various browsers in these situations, as it's not universally consistent. For the scenarios involving adding elements to an open container (e.g., appendChild), the appropriate behavior seems very straightforward--just add the element. Future markup encountered by the HTML parser (after execution of the script block) should then be appended to the existing in-memory DOM. Other browsers tend to agree on this point.

In the case where a parent element is removed (e.g., removeChild, innerHTML, outerHTML) and parsing resumes, the big question becomes: what is the parser's new context? Different browsers answer this question differently. By and large, most other browsers invalidate the parsed context from the point of deletion in the DOM, and "remember" what was deleted such that future parsed markup is ignored until the containing tree (now deleted in-memory) is closed. You can start to see the complexity in this approach, especially if the tree is not well-formed. On the other hand, other browsers take a different approach and "re-base" the parsing context of the current markup at the point of deletion. This results in future markup being inserted in "the wrong place" (a matter of perspective) in the in-memory DOM. For illustration purposes, consider the former as "approach A" and the latter as "approach B." Given the following markup, what do you as web developers expect? I tend to think that approach A is the saner model to follow:

<html> <body>   <div id="container1">    <div>     <span id="span1">First block of text</span>     <script type="text/javascript">      document.body.removeChild(document.getElementById('container1'));     </script>     <span id="span2">Second block of text</span>    </div>   </div>   <div id="container2"></div> </body> </html>

Final DOM tree constructed using each approach mentioned above:

Approach A

Approach B

html |-body   |-div#container2 html |-body   |-span#span2   |-div#container2
What can you do?

In any case, the moral of the story is to avoid getting yourself into this scenario if possible. Granted, in some cases it may be inevitable, especially if the content is not under your direct control (like ad-injection scenarios). Knowledge Base article 927917 mentions some workarounds, but additionally to avoid the problem, you simply need to ensure that your script doesn't meet all three of the conditions I outlined earlier. So, if possible, do the following to avoid an operation aborted error:

  1. Moving your script execution to a function that is invoked after parsing is complete (e.g., onload)
  2. Adding the defer boolean attribute to the script block (this defers execution of the script content until parsing is complete)
  3. Limiting your tree modifications to the script-element's immediate parent
  4. Moving the location of your script block to a child of the body (this usually solves most problems, while allowing the most flexibility in terms of scenarios).

Always a pleasure,

Travis Leithead
Program Manager
IE8 Object Model