graaljs
graaljs copied to clipboard
Js error message became [object Object]
js script exception not being extracted properly after 19.x.x
we noticed that exceptions changes from having actual message (in this case we have some errors from handlebars.js), to having [object Object]
when upgrading from 19.3.1 to 21.0.0, looking at https://github.com/oracle/graaljs/blob/master/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/UserScriptException.java it seems like getMessage
is changed between the versions...
specifically https://github.com/oracle/graaljs/blob/master/graal-js/src/com.oracle.truffle.js/src/com/oracle/truffle/js/runtime/UserScriptException.java#L125 returns null
, and that's from com.oracle.truffle.object.DynamicObjectLibraryImpl
@TruffleBoundary
@Override
public Object getOrDefault(DynamicObject object, Shape cachedShape, Object key, Object defaultValue) {
Property existing = ACCESS.getShape(object).getProperty(key);
if (existing != null) {
return getLocation(existing).get(object, false);
} else {
return defaultValue;
}
}
thinks DynamicObject<JSError>
has no constructor
....
Do you have some example code that you can share that triggers this?
sorry for the late reply, we have the handlebars.js 3.x running, and it's just an error thrown in javascript like https://github.com/handlebars-lang/handlebars.js/blob/v3.0.8/lib/handlebars/runtime.js#L198, the message is lot in between
Hey it seems that Handlebars JS has created their own custom exception which seems to be the problem.
Here is a minimal example that outlines the problem
import com.google.common.io.Resources;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Source;
public class Program {
public static void main(String[] args) {
Engine engine = Engine.create();
Context context = Context.newBuilder()
.engine(engine)
.option("js.nashorn-compat", "true")
.allowAllAccess(true)
.build();
String customErrorFunc = "function customError(errorMessage) { this.message = Error.prototype.constructor.call(this, errorMessage).message; }\n" +
"customError.prototype = new Error();";
try {
context.eval(Source.create("js", customErrorFunc));
context.eval(Source.create("js", "throw new customError('This is a basic error')"));
} catch (Exception e) {
System.out.println(e.getMessage());
// 19.3.1 returns {message: "This is a basic error"}
// 21.1.0 returns [object Object]
}
}
}
I've done some digging and this was introduced in this commit. We were using the "js.nashorn-compat" mode but when they became combined it broke our functionality.
Here is the line in question before - after. (JSUserObject has since been renamed to JSOrdinary).
Would it be possible to add an option to go back to the previous way of displaying errors?
A simple workaround for this would be to set the constructor property on the prototype of the custom error:
customError.prototype.constructor = customError;
With this simple change I see:
customError: This is a basic error
Alternatively, you could use just subclass Error, e.g. class CustomError extends Error {}
It would probably make sense to show the message also without the constructor property. We'll look into that.