Legacy Banking
Troubleshooting
Known gotchas and pitfalls when configuring, integrating with, or upgrading legacy-banking.
Troubleshooting
Cards & ATM
- Cards were ordered/charged but invisible to the ATM. The ATM only recognizes a card if the matching
debit_cardinventory item is present in the wallet with metadata (metadata.card_id). If your inventory bridge'sAddItemsilently drops metadata (e.g.debit_cardis setstack = trueand merges stacks), cards vanish from the ATM/wallet view even though the DB row and charge went through. Turn onConfig.Debugand watch formatchingSlotsAfter=0logs inserver/cards.lua. - "ATM Init SQL error" on boot/use. This points at needing
sql/migrate-pin-plaintext.sql. PINs are stored in plaintext by design; a database still expectingpin_hash/pin_saltwill error rather than fail gracefully. - PINs are never hashed, even though
LB.HashPin/LB.VerifyPin/LB.GenerateSaltexist inserver/server.lua. The card PIN flow (LB.Cards.ChangePin/VerifyPin) compares plaintext directly. This is an intentional threat-model decision (protects against other players, not server operators) — do not attempt to "fix" it by re-hashing without also removing thelegacy-banking:viewPinfeature. - ATM withdrawal rejected with
reason = 'denomination'. The requested amount must be an exact multiple ofConfig.AtmDenomination. Validate this client-side before submitting a custom amount. - ATM target prompt appears on props you didn't intend.
Config.AtmModelsmatches by model globally — any world prop using one of those models anywhere on the map gets the "Use ATM" option, not just the ones you placed. - ATM permanently unreachable, one warning printed at startup.
client/atm.luarequires the legacy-lib target bridge to exposeTarget.AddModel. This is checked once on a 1000ms delayed thread with no retry — an outdated legacy-lib means ATMs never work until you restart after fixing legacy-lib.
Transfers & accounts
- Recipient lookup fails for a phone number or citizen id. This is by design —
legacy-banking:resolveRecipient/LB.Transfer.ResolveRecipientonly accept IBAN strings. Anything else returnsnil, 'bad_iban'. - Transfer fee seems to "disappear".
LB.Transfer.Senddebitsamount + Config.Transfer.Feefrom the sender but only credits the recipient withamount— the fee is not deposited anywhere. - Ledger shows a debit + a refund instead of a clean rollback. If crediting the recipient fails after the sender was already debited, the sender is refunded automatically, but the refund is logged as a plain
Other-category transaction, not a reversal of the original transfer. - Non-boss employees can't transfer out of a society account, and read-only/deposit-only shared members can't be used as a transfer source. This is enforced by design (
LBCanWithdrawfor shared, live boss-flag check for society) — verify your framework bridge reports job/boss status correctly if a legitimate boss is denied. - Offline-recipient transfers depend on your framework's
players.moneyJSON schema. Crediting an offline player writes directly to that column; if your framework's schema differs (not qbx_core-style JSON), this will break.
Society / job accounts
LB.Society.AddMoney/RemoveMoneysilently returnfalse(no error thrown) ifamount <= 0orjobNameis nil — always check the boolean return.- Calling
LB.Society.EnsureExistsagain with a differentjobLabeldoes not update an already-existing account's label. - Resource-name collision risk: this resource
provides'Renewed-Banking'. Running the real Renewed-Banking resource alongside legacy-banking will collide.
Locations / admin tool
- Bank locations don't reflect SQL changes after boot.
legacy_banking_locationsis only read once at first boot to migrate legacy rows intodata/locations.json(via legacy-lib'sStore). After that, all reads/writes go through the JSON store — editing the SQL table directly has no effect. Uselegacy-banking:saveLocation/deleteLocationor the/bankmanage(Config.AdminCommand) tool instead. - Hand-editing
data/locations.json. It has anextIdcounter; editing IDs without updating it risks ID collisions. - Ped preset doesn't appear as configured. Non-freemode
Config.PedPresetsentries are ambient GTA peds that may be missing on heavily modded servers. Placement silently falls back tomp_m_freemode_01if the model fails to load (~2s timeout) — no error is shown. - Client-side ped/blip leak on crash-restart.
client/locations.lua's cleanup only runs on a normalonResourceStopfor this resource — a hard crash-restart path can leak spawned peds/blips. - Remember to broadcast
legacy-banking:syncLocations()after any server-side change to location data outside the built-in save/delete callbacks, or connected clients won't refresh.
Webhooks
- A configured webhook never fires and there's no error.
Config.Webhooks[eventKey]must be an empty string''to disable — there's no separate boolean toggle. Conversely, a malformed (non-empty) URL will likely throw rather than silently no-op, so double-check URLs when enabling.
lb-phone
- The phone app doesn't appear. Registration happens entirely at runtime via
exports['lb-phone']:AddCustomApp(not a staticConfig.CustomAppstable in this resource) — it silently fails ifAddCustomAppisn't available on your installed lb-phone build, or if lb-phone isn't started. - Server pushes to the phone don't arrive.
LB.Push→exports['lb-phone']:SendCustomAppMessageonly reaches a player if they currently have the phone app open, and hard-depends on lb-phone being installed/running — not just legacy-lib/ox_lib/oxmysql. - Phone UI works in browser preview but not in-game (or vice versa).
phone/src/nui.tsrelies onwindow.fetchNui/window.onNuiEventinjected by the lb-phone host; outside lb-phone it falls back to a browser-preview shim meant only for local dev, which won't reach the real server. - Remember: phone NUI calls are prefixed with
phone:internally, and the phone's server callbacks live under the separatelegacy-banking:phone:*namespace — they do not share names with the desktop UI's NUI handlers or callbacks.
Config sync
- UI category filter doesn't match server-tagged categories.
Config.Categoriesmust be kept manually in sync withweb/src/utils/categories.ts. Config.Colors.Greendoesn't reflect what you set. It's overridden at runtime by legacy-lib'sGetAccentColorexport if present, to keep suite-wide theming consistent.