Lewati ke konten utama

JR — Join Result codes

JR (Join Result) is the response field the server sets on world-join replies. It travels in two packet shapes:

  • TTjW (Try-To-Join-World response) — what you get back after sending a join request (TTjW W=…) or a special-world entry (mines(level), nether(level)).
  • GetWorldError — what you get when Gw (Get World) fails before a TTjW ever fires.

JR=0 means the join succeeded. Anything else is a refusal — the world won't load and the bot stays on the menu (or, if it was already in a world, just keeps playing where it was).

Code table

JRMeaningTypical cause
0OKJoin accepted — world streaming begins
1Too many players in serverSubserver at capacity. Try client:setSubserver(name) to a quieter shard.
2Too many players in worldSpecific world is full. Public world overflow — try the same world name with a WB > 0 shard (or just retry; quotas drift).
3Maintenance startingServer is about to bounce. Don't retry immediately; wait for the maintenance window to end.
4Invalid world nameThe W= field failed validation: empty string, illegal chars, length, reserved name.
5Account bannedThe session's account is banned. Co-fields BanState, BPUR, BPl carry scope / reason / permanent-flag. The runtime auto-transitions the bot to the Banned status.
6Admin locked worldOwner / mod has restricted entry. Even though the world exists, the bot isn't on the allow list.
7Account warningA soft-warn state on the account. Often clears after re-login; sometimes precedes a full ban.
8World unavailableWorldfile-side problem: corrupted, mid-restore, missing on the host. Not retry-able from the client.
9Server timeoutClient→server join handshake didn't complete in time. Retry with backoff.
10Incorrect server addressSubserver hint mismatch. Re-resolve via Gw then re-issue TTjW.
11Server exceptionServer-side runtime error processing the join. Retry; if persistent, file a bug on the host.
12Custom join failCatch-all: world-specific entry rule rejected the request (e.g. password world without a key).
13Already in this worldThe session is already inside the requested world. Treated as a no-op; the bot stays in the world without disconnecting.
14Not allowedPermission denied — locale block, age gate, account-tier restriction, etc.

Co-fields on JR != 0

When the server denies a join, additional fields may travel alongside JR:

FieldTypeUsed when
WNstringAlways — the world the join attempt was for.
E / ErrstringFree-form error blurb. Surfaced in the bot's lastError.
BanStatestringJR=5 — scope of the ban (global, world, chat, …).
BPURstringJR=5 — human-readable ban reason.
BPlintJR=51 = permanent, 0 = temporary.

How Seraph reacts

  • JR=0 → status flips to LoadingWorld, the GW/AE bootstrap burst fires, and inventory streams in.
  • JR=5 with ban-fields → status flips to Banned, the bot disconnects, and the dashboard surfaces the ban reason. No automatic retry.
  • JR=13 while already InWorld → logged as "warp failed but still connected", pending_world is cleared, no status change.
  • Any other JR != 0 → status flips to Error with a "Join denied: <reason> (JR=N)" summary on lastError. The bot stays connected on the menu and is available to retry.

Reading JR from Lua

The runtime translates JR != 0 into client:lastError() automatically — most scripts only need that. If you want to see the code itself, register a p:TTjW event:

client:on("p:TTjW", function(msg)
local jr = msg.JR or 0
if jr ~= 0 then
print(string.format("join denied JR=%d wn=%s", jr, msg.WN or "?"))
end
end)