Got a question that the wiki doesn't answer? Ask on the forum (preferred), or join us on IRC.



From Wiki
Jump to: navigation, search

Exceptions can be thrown by various functions at runtime. This indicates that there was some issue with the input data. There is a straightforward way to deal with these errors however, using a try/catch block.


A good example is code that takes a user input. Assume that we want to validate that the user has provided us with an integer like string. We might write the following:

1   @userInput = _getUserInput();
2   @value = integer(@userInput);
3   _doSomethingWithTheValue(@value);

In this case, if the user input procedure returns '2', then the code will work as intended. If it returns 'string' however, it will throw an exception. As it stands, with no exception handling in place, you would see a similar error to this:

CastException: Expecting a double, but received string instead
        <<main code>>:Interpreter:2

This is the default exception handling mechanism. It prints out the exception type, exception message, and a stacktrace. But perhaps we want to print a custom message to the user. In this case, we can trap the exception using a try/catch block, and handle it in a custom way. In this case, we want to "catch" the CastException that is "thrown".

1   try {
2      @userInput = _getUserInput();
3      @value = integer(@userInput); // Can throw CastException
4      _doSomethingWithTheValue(@value);
5   } catch(CastException @e){
6      // This will run if integer(@userInput) throws a CastException
7      msg("The value must be an integer");
8   }

This will message the user if the value is not correct, using a custom error message.


Sometimes, a block of code might throw multiple types of exceptions, and we want to handle each type differently. Perhaps our _doSomethingWithTheValue procedure was capable of throwing an IOException. We could wrap the entire block in a second try catch block, but there's an easier way, using multicatch.

1   try {
2      @userInput = _getUserInput();
3      @value = integer(@userInput); // Can throw CastException
4      _doSomethingWithTheValue(@value); // Can throw IOException
5   } catch(CastException @e) {
6      msg("The value must be an integer");
7   } catch(IOException @e) {
8      msg("There was an error with the disk, and your request could not be completed.");
9   }

Each catch block will only run if the exception thrown matches the type. If an exception is thrown that doesn't match any of the types, it will continue up the stack as if there were no try/catch in place at that point.

Catch clause specificity

When an exception is thrown, the catch clauses are checked one by one, in declaration order, for exception matches. This means that you should order your catch clauses from most specific to least specific. Consider the following code:

1   try {
2      code();
3   } catch(Exception @e){
4      msg("Will catch the exception");
5   } catch(IOException @e){
6      msg("Will never run, because the catch-Exception clause will always catch the exception first, because"
7         . " IOException extends Exception");
8   }

Be sure to always order your catch clauses appropriately.

The exception object

The exception that is thrown is an associative array that has some perhaps useful information in it, such as the exception message, line number, and things like that. Here is an implementation of the default handling, except it is being handled from within the script.

01   try {
02      code();
03   } catch(CastException @e) {
04      @classType = @e['classType'];
05      @message = @e['message'];
06      @stackTrace = @e['stackTrace'];
07      msg(colorize("&c@classType&f: @message"));
08      foreach(@element in @stackTrace){
09         @procedureName = @element['id']; // This could be a procedure or a closure, or a few other things
10         @file = @element['file'];
11         @line = @element['line'];
12         msg(colorize("\t&a@procedureName&f:&6@file&f:&b@line"));
13      }
14   }

The above example demonstrates the complex usage of the exception object. In addition, it's worth noting that if you are having trouble with code, you could get a stacktrace by throwing and catching a custom exception, however, it's more straightforward to use get_stack_trace()

The Throwable type

All exceptions extend the Exception type, which further extends the Throwable type. Another type of Throwable is a the Error type (and subclasses). If you specifically catch Errors, they can be caught, but this is not recommended, as it usually indicates a very severe error. While it is possible to directly catch a Throwable of any type, you should generally not catch that, and instead catch specific types that you are interested in, or Exception, if need be.

Throwing your own exceptions

You may also throw your own exceptions. See the documentation for Template:Functions for more information.

finally clause

Sometimes you may want to run code after the try block, regardless of what happens in the try block, including successful invocation of the code, an exception being thrown and further exceptions being thrown from the catch block, or simply return()ing in the try block. The finally clause can be used to accomplish this. The finally clause must come after all catch clauses, but may be used even if no catch clauses are defined (this is called a try/finally block). This is most useful for cleanup that needs to happen regardless of how the code exited.

There are three specific examples that this might be useful for:

  1. If code within the `try` block exits via `return`
  2. If code within a catch block either rethrows the caught exception, or--accidentally or intentionally--ends up throwing a new one.
  3. If the code within the `try` block encounters an exception for which there is no catch.

Take the following examples:

1   try {
2      @value = codeThatOpensAResource();
3      return(@value);
4   } finally {
5      cleanUpResource();
6   }

1   try {
2      code();
3   } catch(Exception @e) {
4      throw(IOException, "Another exception");
5   } finally {
6      // This section still runs
7   }

1   try {
2      codeThatThrowsANullPointerException();
3   } catch(IOException @e) {
4      // This block won't be run in this case
5   } finally {
6      // This code runs anyways, though the NPE will be thrown further up
7   }

Caused By, and rethrowing

Exceptions might need to be rethrown. This is supported by throw(). For instance:

1   try {
2      throw(IOException, 'message');
3   } catch(IOException @e){
4      if(/* some condition is true */){
5         // We don't care about this exception
6      } else {
7         throw(@e);
8      }
9   }

This can be used if you want to conditionally handle the exception, but continue to throw the exception up the chain in other cases.

You may find that you have to throw an exception due to another exception. To do this, you may also used the Caused By mechanism. This will cause the exception to chain. This is also supported with throw().

1   try {
2      try {
3         throw(IOException, 'ioexception');
4      } catch(IOException @e){
5         throw(CastException, 'castexception'@e);
6      }
7   } catch(CastException @e){
8      msg(@e['causedBy']); // This will be the IOException
9   }

This can be useful for times that you need to throw another exception from within the catch block, but don't want to hide the original exception, or when you need to otherwise wrap the original exception. It is quite useful to know what exception originally caused this chain. This can be accessed from the causedBy index in the exception object.

Old usage

There is an old, now deprecated usage as well, see the article here for information on how to use it. For new code, however, the new format should always be used.

Known Exception Types

Exception types can be added by extension authors, but here is a list (and documentation) for all known exceptions.


An exception which is thrown if the array copied from a byte array is attempted to be written to.

Since: 3.3.1


Thrown if an entity is looked up by id, but doesn't exist.

Since: 3.3.1


Thrown if an entity has the wrong type.

Since: 3.3.1


This exception is thrown if an error occurs when trying to bind() an event, or if a event framework related error occurs.

Since: 3.3.1


This exception is thrown if a value cannot be cast into an appropriate type. Functions that require a numeric value, for instance, would throw this if the string "hi" were passed in.

Since: 3.3.1


If an enchantment is added to an item that isn't supported, this is thrown.

Since: 3.3.1


Indicates a serious error occurred. It is not recommended to catch Error directly, but instead catch a specific subtype.

Since: 3.3.1


Thrown if something is wrong with the event object. Usually this indicates a bigger problem with the server configuration or plugin issue, rather than an error in the script.

Since: 3.3.2


A generic exception. All normal exceptions extend this type.

Since: 3.3.1


This exception is thrown if a function expected a string to be formatted in a particular way, but it could not interpret the given value.

Since: 3.3.1


This exception is thrown if a file cannot be read or written to.

Since: 3.3.1


Thrown if an argument was illegal in the given context.

Since: 3.3.1


This exception is thrown if there is a problem with an include. This is thrown if there is a compile error in the included script.

Since: 3.3.1


This exception is thrown if a value is requested from an array that is above the highest index of the array, or a negative number.

Since: 3.3.1


Some var arg functions may require at least a certain number of arguments to be passed to the function

Since: 3.3.1


This exception is thrown if the user running the command does not have permission to run the function

Since: 3.3.1


This exception is thrown if a function uses an external plugin, and that plugin is not loaded, or otherwise unusable.

Since: 3.3.1


This exception is thrown if a procedure is used without being defined, or if a procedure name does not follow proper naming conventions.

Since: 3.3.1


If a function requests a world, and the world given doesn't exist, this is thrown

Since: 3.3.1


This exception is thrown if a function expected the length of something to be a particular value, but it was not.

Since: 3.3.1


Thrown if data was not found, but expected.

Since: 3.3.1


If a null is sent, but not expected, this exception is thrown. Additionally, this is thrown if null is dereferenced.

Since: 3.3.1


This exception is thrown if a function expected an online player, but that player was offline, or the command is being run from somewhere not in game, and the function was trying to use the current player.

Since: 3.3.1


Thrown if trying to register a plugin channel that is already registered, or unregister one that isn't registered.

Since: 3.3.1


This exception is thrown when a plugin is loaded, but a call to the plugin failed, usually for some reason specific to the plugin. Check the error message for more details about this error.

Since: 3.3.1


This exception is thrown if a function expected a numeric value to be in a particular range, and it wasn't

Since: 3.3.1


Thrown if a field was read only, but a write operation was attempted.

Since: 3.3.1


Thrown if an SQL related exception occurs.

Since: 3.3.1


Thrown if a scoreboard error occurs, such as attempting to create a team or objective with a name that is already in use, or trying to access one that doesn't exist.

Since: 3.3.1


This exception is thrown if a script tries to read or write to a location of the filesystem that is not allowed.

Since: 3.3.1


Thrown if a shell exception occurs.

Since: 3.3.1


Thrown if a stack overflow error happens. This can occur if a function recurses too deeply.

Since: 3.3.1


If an age function is called on an unageable mob, this exception is thrown.

Since: 3.3.1


If an untameable mob is attempted to be tamed, this exception is thrown

Since: 3.3.1

Navigation menu