Intercepting and interracting with a custom Error object in javascript - javascript

I am using a custom javascript modulue which has it's own Error objects. I would like to intercept those custom Error objects and take the appropriate path in my try{} catch{} block, distinguishing them from Javascript's built in Error objects such as ReferenceError, TypeError etc.
So a bit like this.
try {
// Some code that might produce a traditional javascript error
// or one of the errors raised by the module I am using.
}catch (error){
if(error instanceof ExchangeError){
// Handle this in a way.
}else{
// Probably one of the built in Javascript errors,
// So do this other thing.
}
}
So, in the example above, ExchangeError is a custom error belonging to that specific module, however, I am not able to run the instanceof on my error, despite the fact that when I do error.constructor.name I get ExchangeError.
My javascript scope simply does not know about that ExchangeError. So the question is, how can I intercept those kind of Error objects? I'm sure I can do it with string matching, but just wanted to check if there is a more elegant way.
One thing I tried, I have my own errors module, that has some custom errors in there, I tried to mimic the module's Error object:
class ExchangeError extends Error {
constructor (message) {
super (message);
this.constructor = ExchangeError;
this.__proto__ = ExchangeError.prototype;
this.message = message;
}
}
and import that through my errors module, but that did not work obviously.

By actually implementing my own ExchangeError I actually was doing something really really bad, I was blinding the instanceof check with my own ExchangeError, whereas the ExchangeError instance that was coming from the module, was NOT an instance of my own ExchangeError. That is why my if check was falling silent.
The solution is simply doing this:
const { ExchangeError } = require ('ccxt/js/base/errors');
Importing the error from within the module. Now the instanceof look up is working. I did not know that one can import bits and pieces from a module like that.
Thanks to #FrankerZ for pointing that out.

Related

How to check if an exception is a FirebaseError / FirebaseAuthError in TypeScript

I'm trying to implement Firebase authentication and user creation on our server, working on TypeScript.
I'm creating a new user, and I have wrapped the whole creation inside a try-catch block. I'm trying to catch several exceptions, one of them being exception thrown by Firebase.
The problem is that I can't check if the exception was thrown by the Firebase, or if it's another type of exception.
Other answers to similar kind of questions suggest to check if the exception is an instance of FirebaseError:
let firebaseUser;
try {
firebaseUser = await firebase.auth().createUser({
email: email,
password: password,
});
// Other code here
} catch (error) {
if(error instanceof FirebaseError){
// handle FirebaseError here
}
}
The problem is, that when there is an error in the createUser function, the error is an instance of FirebaseAuthError, not FirebaseError, so this check fails.
I tried to switch it to FirebaseAuthError and import the FirebaseAuthError as well, but I get an error message:
Package subpath './lib/utils/error' is not defined by "exports" in
\node_modules\firebase-admin\package.json
So what would be the correct way to check that the caught exception is thrown by FirebaseAuth?
I think the best thing you can do, is writing a type guard to ensure your error is a FirebaseAuthError that you will import using import type. I checked, and it seems that it's because the library doesn't export it.
You can freely benefit from the type used by firebase, however, as the module is not listed in the exports, you won't be able to use it at runtime. the import type syntax allows you to still use it during development, but it will be completely ignored at build time.
That means you can't use instanceof FirebaseAuthError as only the type is imported, and you can't use instanceof on something else than a class.
I'm not sure about the following statement, but I guess that every error prefixed by auth/ seem to be a FirebaseAuthError.
Thus, you could write a type guard as follows:
import type { FirebaseAuthError } from 'firebase-admin/lib/utils/error';
function isFirebaseAuthError(error: FirebaseError): error is FirebaseAuthError {
return error.code.startsWith('auth/');
}

Stop future object properties from being edited

I'm a JS game dev who's been trying to combat tampermonkey scripts for a while now.
I came up with a solution for people hooking into WebSockets where I'd cause the WebSocket to throw an error new WebSocket(0); (0 throws an error due to it being a number)
let output;
try {
output = new target(...args);
} catch(e) {
let source = e.stack.substring(e.stack.indexOf("("), 1 + e.stack.indexOf(")"));
e.stack = e.stack.replace(source, "nothing to see here");
throw e;
}
this code made the error's stack have all the information I was looking for replaced!
I've been looking at Object.defineProperty, and I was wondering how I could stop an error's stack from being modified before I have access to that specific error. And if anyone has any other ways I could stop a script from being loaded or run, I'd love to hear them!
One thing you could do is Object.freeze the error before throwing it. This would prevent people from altering the object's contents.
So for example:
try {
new WebSocket(0);
} catch (wsErr) {
throw Object.freeze(wsErr);
}
The code catching your error and trying to alter it would fail to be able to alter it. This should work as it will cause the code that was altering the error to throw with the following:
Cannot assign to read only property 'stack' of object ''
The other thing you'll have to consider is that in your code where you're catching the error, you will not be able to alter its contents either. Typically with errors, that's not a huge deal though. Tampering with errors is one of the only reasons I can think of for modifying the error.

Disable duplicate declaration validation in Acorn

I'm using Acorn to parse some syntactically valid JavaScript code into an ESTree for further processing. It appears that Acorn does some semantic checks too - in particular it throws an error for duplicate declarations. For example, parsing the following code throws an error of Identifier 'f' has already been declared:
function f() { return 1; }
function f() { return 2; }
I do not want such semantic errors to be checked - I'm doing custom processing on the resultant ESTree, so the semantic validity of the source code does not matter to me.
I've looked though the Acorn options for the parse(input, options) function, but I could not find anything that sounds like what I want.
Is there a way to disable such semantic checking?
It seems like there is no proper way to disable semantic validation. I managed to get what I want with an ugly hack, by overriding the raiseRecoverable method.
This worked for me (note that I'm using TypeScript here, but it would of course be possible to do the same in plain JavaScript):
import { Parser } from "acorn";
class SyntacticParser extends Parser {
raiseRecoverable(pos: any, message: string) {
if (message.includes("Identifier ") && message.includes(" has already been declared")) return;
(Parser.prototype as any).raiseRecoverable.call(this, pos, message); // weird call syntax required because the TypeScript types for Parser doesn't contain the `raiseRecoverable` method
}
}
It's an ugly hack because I'm filtering out the duplicate declaration message based on the stringified error message. However, there does not appear to be a better way.

Is there a way to override the default JS error messages?

I'm guessing the answer to my question is no, but since I don't know enough about how Error.prototype works I figured it was worth asking: is there any way to change the error messages from the errors in Javascript?
For instance, if I get an error:
TypeError: (intermediate value) is not iterable
is there any way to change things such that I instead get:
TypeError: You expected an array but it wasn't an array dummy!
I thought about using a global error handler and then rethrowing them, but that would only work for uncaught errors. Is there any Error.prototype method I can change (or any other way) to do this?
Not at all important, just curious.
EDIT: Just to clarify two points:
1) I understand how try/catch works, but what I'm asking about is whether there is a way to control the messages generated before the error is thrown/caught (presumably by overwriting a method of Error.prototype).
2) An answer of "no there is no way to do this, all generating of JS error messages is handled internally and the JS code has no way to control it" would be perfectly legitimate (... if that's the case).
You have to override the TypeError class, not one of these methods.
const overridableMessages = [{
search: 'TypeError: (intermediate value) is not iterable',
replace: 'TypeError: You expected an array but it wasn\'t an array dummy!'
}]
class TypeError extends window.TypeError {
constructor (message) {
super(message)
overridableMessages.forEach((overridableMessage) => {
if (this.message === overridableMessage.search) {
this.message = overridableMessage.replace
}
})
}
}
window.TypeError = TypeError
window.onerror = function(msg, url, linenumber) {alert('Error : '+msg+'\nURL: '+url+'\nLine Number: '+linenumber);return true;}
// general error handler
Also:
try {
}
catch(err) {
alert(err); // here put your case with your messages.
}
// routine error handler
HIH,
I hate to answer my own question, but I found this line on the MDN which seems to pretty clearly answer things:
The global Error object contains no methods of its own, however, it does inherit some methods through the prototype chain.
Since the only methods it gets through the prototype chain are toString and toSource (neither of which controls an error's generated message), it appears (unless I'm missing some other mechanism that isn't Error.prototype-related) that there is no way to accomplish what I asked.

Throwing custom error doesn't preserve Error formatting in the log

JavaScript, when throw-ing a built-in error as such:
throw new Error("Something was wrong");
displays the text nicely - you can't tell you threw an object
However, when creating a custom error by subclassing the Error object (or other error object for that matter), the thrown error is not displayed the same way in the console.
So, by using this code:
var ImproperlyConfigured = function(message){
this.name ="ImproperlyConfigured";
this.message = message || "The object you tried to construct was improperly configured due to an unknown error";
}
ImproperlyConfigured.prototype = new Error();
The following is the output
I don't like the fact that the object properties (name and message) are shown. In fact, I don't like that I don't understand why the properties are shown.
I've googled a bit and I got the feeling that by implementing a toString method will help but, by using this method, the fact that the name of the error is no longer in red puzzles me even more.
Code
var ImproperlyConfigured = function(message){
this.name ="ImproperlyConfigured";
this.message = message || "The object you tried to construct was improperly configured due to an unknown error";
this.toString = function(){
return this.message;
}
}
ImproperlyConfigured.prototype = new Error();
Output:
What I would like to achieve is a standard looking error, by the use of custom error and, of course, by not using the console.error method manually in a try...catch block.
Is this possible?
As Pointy correctly pointed out (pun intended), the issue here is not with JavaScript, but rather with the environment JavaScript is running (in this case, Google Chrome).
In another environment (like Chromium, Firefox, NodeJS, etc.) the behavior will likely be different, using the same code, depending on how those JavaScript hosts are handling these cases.

Categories

Resources