archives

« Bugzilla Issues Index

#2993 — Store evaluation errors as "failed" modules


Consider the following scenario:

I load two modules simultaneously -

System.import('A').then(function() {
// a completed
});
System.import('B').then(function() {
// b completed
});

A is dependent on B. B has a runtime error in its evaluation.

Linking happens fine, as in A and B are both placed in the module table linked.

But when it comes to evaluation, B is evaluated first and fails. The import promise throws. Yet its module object is still marked as evaluated due to 15.2.6.2 (7).

Now A is evaluated and completes. That is, despite the evaluation failure of B it returns successfully.

That is the import promise for A completes successfully and returns the module object.

Perhaps this is a feature and not a bug? It was a little surprising though.


This is as intended.

While this behavior is potentially surprising, other options are worse. In particular, we can't tell what is a failure of 'B' to properly load, and what is just standard ES code execution which ends in an exception.

Possible alternatives that we rejected include:

- removing linked modules from the table (a very bad idea)
- not running the code for 'A' -- then you have weirdly unexecuted module lying around. When would A get executed?


I can deal with this from the perspective of how the imports operate, but the bad part is not having an easy trace of how the error happened.

Typically when there is an error in my code, I want to know the list of modules loaded that caused that execution to happen in the first place.

If I see an error on some third party library on a random line, that is affecting my code, I need to know why I am even running that third party library in the first place.

ensureEvaluated effectively has this information, as it represents a single line of execution down the module tree, this module list being the exact information the user wants to know at this point.

Perhaps this is the realm of debugging tools, but it needs to be provided to the user somehow, we can't ignore debuggability.


This example looks simply like an example of the fundamental flaw in Promises: if the dev fails to explicitly add a handler for the rejection of import B, then there is no way to know that it failed.

The example is unclear on the import of A. If by "A is dependent on B" means that A imports B, then if B's import throws, A's import must reject.

Any preceding import of B cannot alter this result: its is not a valid module, that is what it means to throw during evaluation.


The proposal is to store modules that fail execution as "failed" in the module registry. And whenever another module imports from a "failed", module it should by default also fail and return a reject promise handler for its import as well.

EnsureEvaluated does maintain an evaluation thread allowing it to report useful debugging information too.

So if I import A, which imports B, which imports C, which imports D, and D throws. We should get:

System.import('B').catch(function(e) {
// e = error description, while executing D, dependency of C, dependency of B
});

That is we can get a useful evaluation stack.

Then when we import from A later, the proposal above would enable this to also error:

System.import('A').catch(function(e) {
// e = Module A imports from failed module B
});

Or something potentially to that affect at least.


works as intended

see Comment #1