Skip to content

ScriptingErrors and the sandbox

When a script goes wrong

Loudly, and then it stops.

  • A parse error or a throw at load disables the script, prints the message with the file and line to chat, and paints its name red in the menu.
  • A file named after an existing module is refused before any of its code runs. It appears in /bitchos script and in errors as broken, with the clash named; rename the file and reload.
  • A throw inside a handler is printed and counted. After five, the script is switched off and says so, because a handler throwing twenty times a second floods the log, costs frames, and buries the first error, which was the only one worth reading.
  • A refusal (an http call to a file:// URL, a command name somebody else owns) is printed but does not count towards that five: the API answering "no" is not a crash.
  • An infinite loop is killed after 2.5 seconds by a watchdog, and lands in the script's error list like any other failure. Without it, one bad loop is a frozen client and a force-quit.
  • /bitchos script errors reprints the last error for every script.
  • Switching a broken script back on in the menu clears its failure count. You have presumably just fixed it.

The sandbox

Scripts run inside a class allowlist. Two independent layers:

No LiveConnect. The global scope is built without Rhino's Java bridge, so there is no Packages, no java, no getClass, no JavaAdapter and no importClass. A script cannot name a Java class at all.

A class allowlist for the classes reachable through objects the host hands over. Allowed:

  • java.util, java.util.regex, java.text, java.math, java.time
  • the safe half of java.lang
  • everything in gg.bitchos.script.api, which is the whole API surface

Refused, with the capability handed back another way:

refused use instead
java.io, java.nio.file storage
java.net http
java.lang.Thread, System, Runtime, ProcessBuilder schedule, scheduleTicks
java.lang.Class, java.lang.reflect — (this is what closes x.getClass().getClassLoader())
net.minecraft.** player, world, render
every bitchos package except gg.bitchos.script.api the bindings
sun.*, jdk.*, com.sun.*, javax.*

The standard library objects (Array.prototype and friends) are sealed, so one script cannot change the language out from under another.

What this is and is not

It is a capability boundary around the game: it stops accidents and casual mischief, and it means a script you have not read cannot quietly read your licence key or write to mods/. It is not a defence against a determined attacker whom you have already persuaded to install their file. Read scripts before you run them.

.jar extensions have none of this. See compiled extensions.