Troubleshooting
Most issues come from one of five sources: boot order, framework/inventory detection, admin access mapping, money/item configuration, or a code-state edge case (expiry, uses, private target). Work through the relevant section below.
The first thing to do for almost any problem is enable debug and read the server console:
F5Cfg.Debug.enabled = true
-- the categories below are on by default; PERF is off
Nothing Happens / Resource Is Inert
Symptom: /redeem or /redeemadmin does nothing; no panel opens.
1. Framework / inventory detected?
The bridge runs detection once at startup. With the BRIDGE and INIT categories on you should see:
[SERVER][BRIDGE] detected framework=qb inventory=qb
[SERVER][INIT] f5_code server ready (framework=qb inventory=qb)
If instead you see an inert message, the resource didn't initialize:
[SERVER][ERROR] [ERR] [BRIDGE] no supported framework detected (esx/qb/qbx) — resource inert
[SERVER][ERROR] [ERR] [BRIDGE] no supported inventory detected for framework esx
2. Boot order
f5_redeemcode must start after oxmysql, your framework, and your inventory. A reversed order means detection runs before those resources exist.
ensure oxmysql
ensure qb-core
ensure qb-inventory
ensure f5_redeemcode
3. Wrong adapter detected?
If detection picked the wrong inventory (e.g. esx_native while you actually run ox_inventory), force it:
F5Cfg.Framework.inventory = 'ox'
F5Cfg.Framework.mode = 'qb' -- only if framework detection is also wrong
Config / Errors About a Missing File
Symptom: Startup errors like couldn't load config.lua, or F5Cfg being nil.
Both config files live in the config/ folder and the manifest loads them from there (config/config.lua, config/config_webhooks.lua). If you moved or renamed them, put them back — or update the paths in fxmanifest.lua to match. Don't reference config.lua from the resource root.
Database Errors / No Driver
Symptom: IO logs about DB failures, or [sql_bridge] no MySQL driver started….
The SQL bridge waits up to 30 s for oxmysql, mysql-async or ghmattimysql to start. If none is up in time, DB calls throw. Ensure a supported driver starts before f5_redeemcode:
[SERVER][IO] [sql_bridge] driver detected: oxmysql
If you disabled autoCreateTables, make sure you imported code.sql and are aware migrations don't run — keep autoCreateTables = true unless you manage the schema yourself. See Configuration → Database.
Admin Panel Denied
Symptom: /redeemadmin shows "You do not have permission to do this."
Access = passes the ACE permission OR belongs to a listed framework group:
F5Cfg.Admin = {
acePermission = 'f5code.admin',
frameworkGroups = { 'admin', 'god' },
}
- Using the ACE path? Grant it:
add_ace group.admin f5code.admin allowinserver.cfg, and make sure your player is ingroup.admin. - Using framework groups? Confirm your character's group is one of
frameworkGroups(QBPlayerData.job/permission, ESX group, etc.). - Set
acePermission = ''to disable the ACE path, orframeworkGroups = {}to disable the group path — but don't disable both, or nobody has access.
With the SECURITY category on, a denial logs admin reject … reason=no_permission.
"Invalid or Expired Code"
A code returns redeem_invalid / redeem_expired / redeem_max_uses / redeem_private / redeem_already_used. Each maps to a specific rule — with the CODE category on, the server logs the exact reason:
| Message | Cause | Fix |
|---|---|---|
redeem_invalid | Code doesn't exist or was deleted | Check spelling; confirm it's live in Active Codes |
redeem_expired | Past its expiry date | Edit the code and extend/clear the expiry |
redeem_max_uses | Reached its use cap | Raise max_uses (or 0 for unlimited) |
redeem_private | Player's Citizen ID isn't a target | Add their Citizen ID to the code's targets |
redeem_already_used | This player already redeemed it | Expected — each player may redeem a code once |
redeem_cooldown | Retried too fast | Wait cooldownMs; raise it only if needed |
If a code that "should" match is rejected, check F5Cfg.Codes.caseInsensitive. With it true (default) SUMMER and summer match; with it false they don't.
Money Not Granted
Symptom: Redeem succeeds but the player's balance doesn't change.
- The target money account must be active for your framework.
cryptohas no ESX account andblackmoneyhas none on QB/QBox, so those types are skipped there. See Framework Compatibility → Money. - For legacy single-amount codes, payout goes to
F5Cfg.Money.payoutType— make sure it's a valid, active type (falls back tobank, then the first active type). - With the
REDEEMcategory on, a failed credit logsfailed to add money …. That usually means the account key doesn't match your framework's real account name — check theaccountsmapping inF5Cfg.Money.types.
Items Not Granted / "Not Enough Inventory Space"
redeem_inventory_fullmeans the player couldn't carry all items — the redeem is refused and nothing is granted (by design). Have them free space and retry.- If items silently don't appear, confirm the item names exist in your inventory and the inventory adapter is the right one. A
REDEEMlogfailed to add item …points at a bad item name or a full slot. - Amounts are clamped to
1 … F5Cfg.Rewards.maxItemAmount; distinct items beyondmaxItemsare dropped at create time.
No Item Images In The Panels
Item icons use the detected inventory's image path. If they're missing or from the wrong inventory, override it:
F5Cfg.Inventory = {
imageUrl = 'nui://ox_inventory/web/images/%s.png',
}
%s is the item name. See the per-inventory paths in Framework Compatibility → Inventories.
Private Code Won't Save / Target "Doesn't Exist"
Symptom: Creating a private code fails with admin_targets_not_found or admin_target_unverifiable.
admin_targets_not_found— one of the Citizen IDs isn't in the player database. Double-check the ID, or use Choose from list to pick an online player.admin_target_unverifiable— the bridge couldn't query the player table (wrong table/column for a fork, or a DB error). For a custom framework, setplayersTable/uidColumn. See Framework Compatibility → Custom framework.- To skip DB validation entirely (trust the entered IDs), set
F5Cfg.Codes.validatePrivateTarget = false.
Webhooks Not Sending
- Confirm the master switch:
F5Cfg.Admin.auditWebhook = true. - Set
Webhooks.defaultUrl(or the event's ownurl) to a real Discord webhook. - The URL must match
Webhooks.urlValidationPattern; a rejected URL logsurl rejected by patternunder theWEBHOOKcategory. - Check the event's
enabled = true.
See Webhooks.
A Deleted Code's Name Won't Free Up
Reusing a deleted code's name relies on the code_active generated column, which needs MySQL 5.7+ / MariaDB 10.2+. On older servers the migration is skipped (you'll see a [DB] error about it) and the legacy unique key is kept, so old names stay reserved. Upgrade your database engine to enable name reuse.
Still Stuck?
- Turn on
F5Cfg.Debug.enabledand theSECURITY,CODE,REDEEM,ADMINandIOcategories, then reproduce the issue and read the server console — the exact rejection reason is almost always printed. - Join the F5 Studio Discord for support.
See Also
- Installation — requirements and start order
- Configuration — every option
- Framework Compatibility — detection, money and adapters
- Features — the full redeem validation order