Skip to main content
Almost everything a plugin does wrong is written to the client log rather than to chat, so that a misbehaving plugin cannot spam you. Open logs/latest.log in your game folder and search for [Seraph].

The plugin does nothing at all

There are two switches and both have to be on. Run /seraph config, open the Plugins tab, and check the master switch as well as the plugin’s own toggle. While a plugin is disabled it is never run: its listeners are skipped when an event fires, its commands are not registered and every gated call it makes is refused. Enabling it takes effect at once, though a plugin that registers things at load time needs a reload with /seraph plugin before you see them.

The plugin is not in the list

Seraph only discovers .js files sitting directly in the plugins folder. A file in a subfolder is not loaded, though a loaded plugin can still require one. Check the path: If the file is in the right place, it threw while loading. The log names the file and the error.

One call does nothing, the rest works

That call needed a permission the plugin never asked for. The log says so once per plugin and permission:
Add it to permissions in declareModule and reload. Because the warning is printed only once per permission for the life of the client, restart if you want to see it again.
console, scheduler, input, text, party and the event listeners themselves are ungated, so a plugin that logs happily but cannot send chat is almost always missing "chat".

The plugin stops after a while

Seraph stops a plugin that will not yield rather than letting it hang the client. Loading a plugin has ten seconds, and anything dispatched into it, an event, a command or a timer, has two. Passing the budget stops that plugin and leaves the rest of the client running. The usual causes are a loop with no exit, a synchronous wait, or heavy work in tick, renderOverlay or an anti-cheat check. Move slow work onto a timer, and keep hot callbacks to arithmetic.

Edits to a module are ignored

A file named <name>.mod.js is a module. It is compiled once and stays loaded for the life of the client, so neither the folder watcher nor /seraph plugin swaps it out; Seraph tells you in chat that a restart is needed. Ordinary scripts carry on reloading around it. If you are iterating on something, work in a plain .js script and rename it once it settles.

The plugin is skipped with a reason in the log

Everything in dependsOn has to be present and enabled. If one of them is missing or switched off, the plugin is skipped entirely rather than failing part way through, and the reason is logged. Plugins that depend on each other in a circle are all still loaded, but the order between them is arbitrary and the circle is reported.

A command did not register

Two things stop a command appearing:
  • The plugin was disabled when it tried to register, which is logged.
  • The name is already taken. Seraph refuses to overwrite an existing command and logs command '/x' already occupies registry space, so pick another name.
Commands need the commands permission, and anything the command prints needs chat.

A listener never fires

Check the spelling first. An unrecognised event name is accepted, but the log warns that nothing will ever fire it and prints the full list of names that do exist. If the name is right, the event may not mean what you expect. playerMove is the position the server puts you at rather than every step you take, playerJoin follows the tab list rather than the world, and tick only fires while you are in a world. The full list is in Events.

Nothing is drawn on screen

renderOverlay only fires while you are in a world and no screen is open, so an overlay is hidden whenever the inventory, chat or a menu is up. Drawing also needs the render permission, and the coordinates are in scaled screen pixels, so use render.getScreenWidth() and render.getScreenHeight() rather than hard-coded numbers.

Requests start failing

The network permission is rate limited to 30 requests per minute per plugin, counted across http.fetch and stats. Past that, calls are refused until the window rolls on. A chat listener in a busy lobby can pass that in seconds, so match narrowly, or collect what you want to send and flush it on a timer.

A cron schedule never runs

cron returns -1 when the expression cannot be read. Check the return value:
It takes the usual five fields, minute, hour, day of month, month and day of week, aligned to the wall clock rather than to game time.

Settings do not survive a restart

Writing to config changes the live value, but only savePluginConfig() writes it to disk:
storage is separate and has its own save(). Use config for settings the user is meant to change in the menu and storage for data your plugin manages itself.

The editor does not know the API

plugins/seraph.d.ts is rewritten every time plugins load, so load them at least once and make sure your editor has the plugins folder open as its project root. A jsconfig.json beside your plugins makes it stricter, as described in Getting started. If completion is stale after a Seraph update, reload plugins so the file is regenerated against the build you are actually running.