Skip to content
Jiří Cihelka edited this page Dec 30, 2023 · 2 revisions

When the library encouters an unexpected problem or an illegal call is made, it throws an error using the throw keyword. All errors thrown by the library extends the built in Error class and if they are library specific then they also extend the GeometryJSError class.

GeometryJSError

The GeometryJSError class is a base class for all errors thrown by the library. It extends the built in Error. It is also extended by other errors in the library. Other errors can be found in the ./src/errors directory.
It also adds a few properties to the Error class:

  • id - A unique identifier of the error. This is useful for debugging, as you always know which error was thrown. It is also useful when submitting an issue, as you can easily reference the error. The id is a string. It is constructed from identifiers of the error and all of its parents seperated by a dot. The last dot-separated value is the identifier of the place from which the error is thrown.
  • timestamp - A number representing the time when the error was thrown. This can be useful in specific cases, when you want to know the time of the error.
  • description - An optional string describing the error. It is the first step when diagnosing the error.

Error handling

When the library throws an error, it is usually an unexpected error. This means, that using the library as intended should not throw any errors. If you want to handle an error, you should use the try/catch statement.

try {
    // code that can throw
} catch (error) {
    // handle the error
}

If you only want to handle errors of a specific type, you can use the instanceof operator.

try {
    // code that can throw
} catch (error) {
    if (error instanceof MyError) {
        // handle the error
    } else {
        throw error;
    }
}

Or if you don't want nested if else statements, you can use a labeled code block.

try {
    // code that can throw
} catch (error) {
    handleError: {
        if (error instanceof MyError) {
            // handle the error
            break handleError;
        }
        if (error instanceof MyOtherError) {
            // handle the error
            break handleError;
        }
        throw error;
    }

}

Debugging

As all the errors contain an id, you can easily look up the error on the wiki. The wiki contains a list of all errors and their descriptions.
You can also use the description property of the error to get a more detailed description of the error without looking it up on the wiki.

Adding errors

We follow a practice of creating a new error for every situation, that can be found in more than one place. This way, the name of the error is in most cases descriptive enough to know what the error is about.

Properties of an error

If there is any additional information the error can provide, it can be added as a property of the error. If some properties of the error are not standard, the error should also override the toJSON method. This method is used by JSON.stringify to convert the error to a JSON string. This is useful when sending the error to the user or when logging the error.

Error hierarchy

When creating an error, always consider if it can be a child of an existing error. If it can, it should be. This way, the error hierarchy is more consistent and the errors are easier to find and can be easily separated using the instanceof operator.

Handeling errors inside the library code

The library code should not rely on error handling in its logic. We should always follow the practice of throwing an error when the library encounters an unexpected problem, that we cannot solve in another way.

NaN and Errors

Returning NaN can sometimes seem similar to throwing an error. We establish a standard, that NaN should be returned only when the result cannot be any number. Differece between NaN and an error is, that returning NaN is way faster than throwing an error. We can use NaN in many operations and treat it as a number (comparing it to other numbers).
Returning NaN can also be seen as an non-fatal error. This means, that the library can still function normaly, only all the affected values will be NaN.
The advantage of this can be seen, for example, in a case when you randomly read an illegal value. If no calculations depend on it, everything will continue to work. If some calculations depend on it, they will return NaN and the error will be propagated to the user.

Strict Error NaN mode

While it is not yet available, we plan to add a strict mode, that will throw an error when NaN is encountered or should be returned. This will be useful for debugging, as it will allow us to find the source of the NaN value.

Clone this wiki locally