Errors

A closed vocabulary defined in @open-rgs/contract. The orchestrator surfaces these codes on the wire as ERROR frames (0xff) with shape { code, message }.

Codes

CodeFires when
INVALID_FORMATframe byte is not a known message code
DECODE_ERRORmsgpack payload couldn't be decoded
MISSING_SESSIONrequest needs sid but none was supplied or attached
SESSION_NOT_FOUNDplatform openSession rejected the id
SESSION_INVALIDsession exists but is closed / blocked / expired
INSUFFICIENT_BALANCEpre-flight check failed for the requested bet
INVALID_BETbetIndex out of range, or bet ≤ 0
INVALID_MODEmode id unknown, internal, or wrong kind
INVALID_ACTIONSTEP action.type doesn't match awaiting.type
INVALID_ROUNDCLOSE on a non-terminal round, or STEP on a terminal one
ROUND_ALREADY_OPENOPEN issued while a round is already in flight
NO_ROUND_OPENSTEP / CLOSE issued with no round in flight
MAX_WIN_REACHEDround multiplier × bet exceeded the manifest cap; win clipped
GAMES_API_UNAVAILABLEplatform adapter isHealthy === false
INIT_FAILEDuncaught failure inside init
SPIN_FAILEDuncaught failure inside spin
OPEN_FAILEDuncaught failure inside openRound
STEP_FAILEDuncaught failure inside stepRound
CLOSE_FAILEDuncaught failure inside closeRound
INTERNAL_ERRORcatch-all; check /admin/logs

Throwing from adapters & math

import { RGSError } from "@open-rgs/contract";

async settleSimple(req) {
  if (response.status === 402) {
    throw new RGSError("INSUFFICIENT_BALANCE", "wallet declined");
  }
  // ...
}

Throw RGSError from adapter methods to surface a specific code; the orchestrator forwards it to the client as-is. Plain Errors become INTERNAL_ERROR. From Lua math, raise error("INVALID_ACTION: ...") — messages starting with a known code map to that code; everything else becomes *_FAILED for the active call.