EteRNAScript error throwing does not return error thrown

I had previously written code, in which I had done some error checking and threw an error if there was an issue. The error I threw nicely printed in the output box as the return. Currently, when I throw an error, the return is undefined.

Also, though it’s probably unrelated I think it may have come up at the same time, I also found out when starting from a copy of a script, I couldn’t delete inputs already defined, and when I tried to call the content of an input I added it gave me the content of the previous input (which was already defined from the original script).

1 Like

On the surface, this sounds like

  • in the first case, the error occurred inside a try block, and a catch block (the exception handler) returned the error message as the value of the program.
  • in the second case, either there was no active catch block, or if there was, it didn’t return the error message as the value of the program.
    In Javascript, the default action if an exception occurs is to simply abort the program.  If you want something else to happen, like display an alert, or return the error message as the value of the program, or something else, you have to explicitly code it.

I don’t mean to insult you if you already know this and something more subtle is going on.

This is one example of the code I wrote:

 if (labSearchType != "" && labSearchType != "title" && labSearchType != "id") { throw "labSearchType invalid. Please either enter title, ID, or leave blank."; }

When I ran it when I first submitted the script, it did return the error message.

That’s different than either of the two cases I described above.  When you use throw, you are actually creating a new exception.  What happens in response to that exception is controlled by code that wouldn’t be shown in the snippet you pasted here.  From your description, the simplest explanation would be that this was inside a try block that had an exception handler that returned the exception text as the value of the program. But active exception handlers get pushed on the call stack, and are executed in the reverse order in which they have been activated, so the exception handler that converted the exception object into a return value for the program might have been far away in the code.

I didn’t write a try block myself, so it would make sense that the EteRNAScript code might have done that. I’m wondering why this no longer works.

Unless my memory is that bad and it never actually worked, but I’m pretty sure it did.

Yeah, indeed when looking at the scripting interface code on GitHub, I found where the code is actually executed. There is a try/catch which returns the error when there is no web worker support , and with web worker support it seems that the script is run with a try catch that does return an error with the catch. The default errors are still returned, just not a custom thrown error, which is really odd.

This code is old, but it does show that, at least previously, this existed. If it was removed for custom errors for some reason, I’d like to know why, and otherwise something must have been bumped to break it and I’d like to see it fixed.

You’re on the right track for figuring it out.  But as you say, that code is old.  So fire up the Chrome debugger and find out what is actually happening with the current code. 

Here’s where the script is executed, and the default outline stuff happens (the else is always taken, I checked):

BuilderScriptPage.prototype.on\_evaluate\_with\_var = function(input, code, timeout\_sec, cb) { var \_this = this; code = ScriptInterface.insert\_timeout(code, timeout\_sec); return this.dynamic\_load(code, function() { var result; result = ScriptInterface.evaluate(input + code); if (cb) { return cb(result); } else { Pervasives.outln("
Return : " + result['cause']); return Pervasives.outln("Evaluation time : " + result['eval\_time'] / 1000 + " sec"); } }); };

And the Evaluation function:

evaluate: function(source) {

var Lib, Library, RNA, RNAElement, RNAException, code, ret, \_global\_timer; this.evaluate\_init(); ret = {}; try { Library = this.Lib; Lib = new Library(); RNA = this.RNA; RNAElement = this.RNAElement; RNAException = this.RNAException; \_global\_timer = new Date(); code = '(function(){' + source + '})()'; ret['cause'] = eval(code); ret['result'] = true; ret['eval\_time'] = (new Date()).getTime() - \_global\_timer.getTime(); return ret; } catch (Error) { ret['cause'] = Error.message; ret['result'] = false; ret['eval\_time'] = (new Date()).getTime() - \_global\_timer.getTime(); return ret; }

This is where it would be at, no idea where the differentiation comes in. A caught error should be a caught error, and it is printed…

Try actually stepping through the code, looking at relevant data.  

Hint: It has to be handled in a catch block, or perhaps code executed from the catch block, if the catch block’s parameter gets passed to a subsidiary function.

Ok, I can see that when the eval() is run, it returns undefined, not my error. I have no idea why this would be, and the difference from, say, a syntax error.

http://prntscr.com/8t56nz

“I have no idea why this would be” - that’s why you are debugging it, so you can see exactly whats happening.

Hint: you’ll want to be watching the variable values, not just the code.

I understand that, and the variable value assigned when the error is caught is ‘undefined’, yet I threw an error message.

However, if I throw an object like this, it works?

function UserException(message) { this.message = message; this.name = "UserException"; } throw new UserException("InvalidMonthNo");

Shouldn’t both work?

I was just writing it as

throw "Test"; 

It seems that doing it like this works

throw new Error('test');

But the info on Mozilla and W3Schools say otherwise, that just writing a constant should work?

As far as the language is concerned, its OK to throw something other than an Error object.  But if you throw a text string, it doesn’t magically get converted to an Error object; it’s still a text string.

But the Eterna-specific environment that handles any exception that your code didn’t catch and tries to return the text associated with it is

      } catch (Error) {        ret['cause'] = Error.message;
        ret['result'] = false;
        ret['eval\_time'] = (new Date()).getTime() - \_global\_timer.getTime();
        return ret;

This assumes that Error is an object, not a string. If Error is a string, as it is in this case, Error.message evaluates as nil.  If you were to keep stepping through from here, you would undoubtedly find  the UI code that “prints” the ‘cause’ property of the ret object returned here.  

You can verify all this by executing the program

throw {message: 'test'}; 

Here, there is no Error object, but there is an object with a ‘message’ property, which is all the Eterna code cares about.

2 Likes

Ah, I did not realize this! I had jumped to the conclusion that it was ‘magically converted’, and by being an error if it wasn’t assigned then it would be assigned to an object with the message property.

Thanks for helping me Omei, you’ve definitely gotten me to learn (and for whatever wasn’t new, realize) a few important lessons along the way. :slight_smile: