Skip to content

Errors and the sandbox ​

Error model ​

The scripting API reports a failure in one of two ways, depending on whose mistake it is.

nil, err: the server said no ​

A call that is well formed but cannot be done returns nil and a readable error message instead of raising. On success it returns true, a handle or the value it reads.

lua
local ok, err = player:set_health(100)
if not ok then
    print("set_health failed: " .. err)
end

local vehicle, err = dlmp.create_vehicle({ model = 411, x = 2470.0, y = -1660.0, z = 13.3 })

Typical reasons: the element is gone (a player who left, a destroyed vehicle), a value is out of range, or the current state forbids it (a seat that is taken, a wreck). The server checks every request itself; the message is for logs and for the player, not for parsing. A few lookups answer nil without a message when there is simply nothing to find: dlmp.get_player(id) for a free id.

Raised errors: the script is wrong ​

A programming mistake raises a Lua error inside the running callback:

  • an argument of the wrong type, a missing required field, or a handle of the wrong family (dlmp.destroy_vehicle(pickup));
  • a string outside a fixed set where the API names one (an unknown priority, an unknown option field where the reference says so);
  • a call that reads or changes the game at load time, at the top level of a script or module: the server is reachable only from callbacks, while registration (dlmp.add_event_handler, dlmp.add_command_handler, dlmp.add_console_command, dlmp.set_timer, require, dlmp.import) works at load time;
  • dlmp.import of a resource that is not a declared dependency, and a call through an import that cannot be made (Calling other resources);
  • a require that cannot load its module;
  • the time limit.

pcall catches a raised error like any Lua error. The reference dlmp.lua notes the cases that raise where the rules above do not make them obvious.

Errors in callbacks ​

An error that escapes a callback is logged with its resource and stops only that callback. The resource keeps running, and what the callback already did before the error stays done: the server applies each call when it is made, there is no rollback.

CallbackWhat an escaping error does
top-level script code, a module loaded at startthe start fails and is rolled back (Start)
resource_start handlerthe start fails; what the start created is removed
resource_stop handlerlogged; the stop goes on
handler of a refusable eventlogged; counts as a refusal; the other handlers still run
player_auth handlerlogged; the connection is turned away, unless the handler had already accepted or rejected it
any other event handlerlogged; the other handlers still run
player command handlerlogged; the command is not consumed and the next handler runs
console command, timer, storage, view, dialog, menu and offer callbackslogged; a repeating timer keeps running
an exported functionraised again in the caller, at the import call

Refusable events fail closed ​

A refusable event (Refusable events) is refused when any handler returns false, raises an error or runs past the time limit, also when the handler caught the time-limit error itself with pcall. A broken filter therefore blocks what it was meant to judge instead of letting it through (ADR 0038). The same holds for the auth resource: a player_auth handler that fails turns the connection away.

Sandbox and runtime limits ​

The sandbox keeps a broken or hostile resource from trivially taking over the server process: a resource has no file, process or network access of its own and cannot stall the server for long with an endless loop. It is not complete isolation: there is no memory limit, so a server should run only resources its operator trusts.

One VM per resource ​

Every resource runs in a Lua 5.4 VM of its own. Resources share no globals, tables or handles; they meet only through exports, whose arguments are copied (Calling other resources). Scripts never see the server's internals, the network or the wire protocol: they act only through dlmp.

Libraries ​

AvailableNot available
the base library without load, loadfile and dofile; print writes to the server log, tagged [lua:<resource>]os, io, debug, package
string, table, mathcoroutine, utf8
require for the resource's own modules (Modules)native modules

Files and network ​

A resource has no general file, process or network access. It reaches only:

  • its own .lua modules, read through require;
  • its own map documents in maps/<name>.toml, read and written through dlmp.read_map, dlmp.save_map, dlmp.list_maps and dlmp.load_map (ADR 0043);
  • its own storage namespace through dlmp.db (ADR 0054);
  • its client files, which the server reads at start and serves to players.

Time limit ​

Every entry into a resource's Lua code has a budget of 1 second of wall-clock time: a script or module at load, an event handler, a command, a timer, a callback and an exported function called by another resource (which gets a budget of its own).

  • The VM checks the budget every 10 000 instructions. Past it, the check raises resource callback exceeded the time limit, and keeps raising at every later check, so catching it with pcall does not buy more time.
  • A single long library call, such as sorting a huge table, is noticed only after it returns.
  • The error is handled like any other error of that callback (Errors in callbacks); the VM goes on running.
  • A resource that has slow work to do splits it over timers; storage requests run off the main loop by design.

Memory ​

There is no memory limit per VM. A resource that keeps allocating can exhaust the memory of the whole server.

Threading and timing ​

  • All Lua code runs on the server's main loop, one callback at a time; nothing runs in parallel, and no callback is interrupted by another. A callback runs to its end before the server goes on.
  • Without coroutines a callback cannot wait. Work that takes time answers later through a callback: storage requests in a later server step, a player's dialog answer when it comes, a timer when it is due.
  • A server step has one time (ADR 0046); timers count from the time of the step that set them.
  • Recursion between resources is bounded: an export call nested more than 16 deep raises an error.

Documentation licensed under CC BY 4.0. DarqlineMP is not affiliated with Rockstar Games or Take-Two Interactive. Grand Theft Auto is a trademark of Take-Two Interactive Software, Inc.