F5 StudioF5 Studio
Skip to main content

Troubleshooting

Most issues come from one of five sources: boot order, inventory/target detection, permission mapping, database state, or a DUI/rendering edge case. Work through this page in order — the symptom you have is almost certainly here.

Board Item Is Not Usable

Symptom: Using the board item from the inventory does nothing — no notification, no placer.

1. Item is registered?

Use the item once with the inventory open. If the icon is broken (?) or the label says the raw id (corkboard), the item isn't registered in your inventory at all. Re-do step 5 in Installation.

2. useable flag set?

For QBCore (shared/items.lua), useable = true is required. If you copy-pasted the entry but the inventory still doesn't trigger anything, double-check that field.

For Qbox / ox_inventory, the equivalent is consume = 0 or consume = 1 — both make the item useable; the difference is only whether it's consumed. F5 Board ships with consume = 0 because the script handles item removal itself (only when Config.Command.requireItem = true).

3. Boot order

Confirm f5_board starts after the inventory and the framework:

ensure qb-core
ensure qb-inventory # or ox_inventory, qs-inventory, …
ensure f5_board

A reversed order means CreateUseableItem runs before the inventory exists, the registration is silently lost, and the item stays inert.

4. Job whitelist (Config.AllowedJobs)

If Config.AllowedJobs is set, only matching jobs can use the item. Test by temporarily clearing it:

config/config.lua
Config.AllowedJobs = nil

Restart. If the item now works, your job spec was rejecting the player. Open the server console — the script logs a SECURITY warning showing the player's job, grade, and the reason (job_not_in_list / low_grade).

5. Bridge detected the right inventory?

Enable Config.Bridge.debug = true in framework_config.lua and restart. The bridge prints what it picked:

[f5_board] bridge: framework=qb
[f5_board] bridge: inventory=qb

If the adapter is wrong (e.g. esx_native while you actually run ox_inventory), force the right mode:

config/inventory_config.lua
Config.Inventory.mode = 'ox'   -- or 'qb', 'qs', 'tgiann', 'codem', 'ps', 'esx_native'

Board Spawns but Has No Target / qb-target Options

Symptom: The prop appears in the world, but there are no interaction options on it.

1. Target system detected?

The bridge only logs an explicit target line when an override is set. With Config.Bridge.debug = true, an override looks like:

[f5_board] bridge: target override → resource=ox_target basedOn=ox

Without an override the bridge uses the framework default (QB → qb-target + qb API, others → ox_target + ox API). If you're on QBCore but actually running ox_target, force it:

config/target_config.lua
Config.Framework.target = {
resource = 'ox_target',
basedOn = 'ox',
}

basedOn must match the API the resource actually exposes — 'qb' for positional AddBoxZone, 'ox' for options-table addBoxZone. Mismatched API throws at runtime (errors visible in the server console).

2. BoxZone is misplaced

The default BoxZone size is derived from the prop's bounding box. For a custom prop with a broken bounding box, it can land off-center.

Turn on debug visualization:

config/config.lua
Config.Target.debugPoly = true

The script draws the BoxZone outline in cyan. Tweak Config.Target.zonePadding (add padding around the model) or Config.Target.fallbackZoneSize (replace the model-derived box with a fixed size).

3. Distance

Default interaction range is 5.0 m. Boards mounted on tall walls can be out of range:

config/config.lua
Config.Target.distance = 8.0

Board Spawns but Content Is Blank

Symptom: Other players' content shows up empty; the board itself renders fine.

1. DUI activation

DUIs only activate within Config.Dui.renderRadius (25 m default). Walk closer.

2. Idle timeout

Boards that haven't been observed for 30 s deactivate their DUI. Walking close should re-activate them within ~1 s. If they stay blank:

config/config.lua
Config.Debug.enabled = true
Config.Debug.categories.RENDER = true

Check the console — RENDER logs show activation / fade-band / idle decisions per board.

3. Player just teleported

After a teleport (/tp, framework teleport menus, vehicle spawn), the board needs ~1 s to receive the bulk-spawn event and recreate the DUI. The script handles this via f5_board:client:requestDuiRecreate — if you're seeing persistent blanks after teleport, check that nothing in your custom code is suppressing that event.

4. Image notes specifically

If only image notes are blank but text notes show up, the image cache isn't reaching the client. Confirm:

config/discord_webhook_config.lua
Webhooks.imageCache.enabled = true

And the image URL itself is reachable from the server (firewall, DNS).

"Permission Denied" on /board or /badmin

Symptom: notify_no_perm ("No permission") on commands the player should have access to.

1. Confirm the framework's native permission

QBCore
qb permissions list <serverId>

Should show admin (or whatever permission node you set).

QBox

QBox uses ACE — confirm:

server.cfg
add_ace group.admin admin allow
add_principal identifier.steam:XXX group.admin
ESX

Check the users.group column:

SELECT identifier, `group` FROM users WHERE identifier LIKE 'steam:%XXX%';

Should return admin or superadmin.

2. Enable SECURITY debug to catch rejections

config/config.lua
Config.Debug.enabled = true
Config.Debug.categories.SECURITY = true

Then when the player runs /board or /badmin and gets denied, the server console shows the rejection:

[SERVER][SECURITY] [WARN] catalog_request_reject src=12 reason=no_perm
[SERVER][SECURITY] [WARN] admin requestList denied src=12

That confirms the permission check ran but returned false. From there, double-check the nodes.<logical>.<framework> mapping in framework_config.lua and the player's actual group / ACE membership.

3. Mismatched logical → real mapping

Look at Config.Permissions.nodes.admin in config/framework_config.lua. The qb / qbx / esx / ox field must contain the real identifier in that system.

For example, if your ESX server uses a custom group 'staff' instead of 'admin':

config/framework_config.lua
Config.Permissions.nodes.admin.esx = { 'staff', 'admin', 'superadmin' }

4. Mixed setup needs aceFallback

If some admins are framework-native and others are pure ACE, flip the fallback:

config/framework_config.lua
Config.Permissions.aceFallback = true

See Permissions for the full reference.

/board Catalog Shows "MISSING ITEM" on Everything

Symptom: Config.Command.requireItem = true, and every tile is dimmed even though the player owns the items.

1. Inventory adapter mismatch

The dimmed-tile check calls Bridge.GetItemCount(src, item). If the bridge is using the wrong inventory adapter, the count comes back 0 regardless.

Confirm the adapter (see Board Item Is Not Usable → 5). Force-set Config.Inventory.mode if needed.

2. Item name mismatch

The item name in Config.Boards[].item must match the item name registered in your inventory exactly (case-sensitive). The default config uses lowercase names; some servers use uppercase or prefixed conventions.

Cross-reference your inventory's item list against Config.Boards.

Webhooks Not Arriving

Symptom: Boards are being placed / renamed / edited / deleted but nothing arrives in Discord.

1. URL set

Either Webhooks.defaultUrl or events[name].url must be non-empty. Both empty → the event is silently skipped.

2. Event enabled

Confirm events[name].enabled = true.

3. URL is valid

The script warns (not hard-fails) on URL pattern mismatch. Enable webhook debug:

config/config.lua
Config.Debug.enabled = true
Config.Debug.categories.WEBHOOK = true

When everything works you'll see:

[SERVER][WEBHOOK] enqueue type=json kind=create tag=7 queue=1
[SERVER][WEBHOOK] sent ok type=json kind=create tag=7 status=204

If you see a skip eventType=create reason=no_url line, the URL didn't resolve — re-check Webhooks.events[name].url and Webhooks.defaultUrl:

[SERVER][WEBHOOK] skip eventType=create reason=no_url board=7

4. HTTP 4xx

If a request comes back with a 4xx status (and it's not 429), the queue drops it with a warning:

[SERVER][WEBHOOK] [WARN] drop status=404 type=json kind=create tag=7 err=...

The webhook URL is wrong. Discord returns 404 for revoked / deleted webhooks. Generate a new one in Discord channel settings.

5. HTTP 429 — rate limited

[SERVER][WEBHOOK] [WARN] rate-limited retry-after=2.5s kind=create tag=7

Honored by the queue. If you see chronic 429s, lower the throughput:

config/discord_webhook_config.lua
Webhooks.queue.tickMs = 500   -- from 250 → 500 (2/s instead of 4/s)

6. Edit event specifically — screenshot missing

The edit event drops if the offscreen NUI render doesn't return a base64 screenshot in time. The client render budget is fixed at 8 seconds. If only create / rename / delete arrive but never edit, check:

  • The client console (F8) for canvas / image-loading errors during the screenshot phase. Image notes with broken / slow URLs are a common cause.
  • The server console for these lines:
    [SERVER][WEBHOOK] edit skip mutationCount=0 board=7      -- nothing was changed in the session
    [SERVER][WEBHOOK] edit skip hash unchanged board=7 -- changes were undone before close
    [SERVER][WEBHOOK] edit skip no screenshot board=7 -- client timed out / failed
    [SERVER][WEBHOOK] [WARN] editSession:end screenshot too large src=... -- payload too big

If "screenshot too large" appears, raise the cap:

config/discord_webhook_config.lua
Webhooks.screenshot.maxBase64Bytes = 10 * 1024 * 1024   -- raise from 7 MiB

Boards Disappear on Restart

Symptom: Boards are gone after restart f5_board (or full server restart).

1. Database connected

The script requires oxmysql (or mysql-async / ghmattimysql). On startup, with Config.Debug.enabled = true and Config.Debug.categories.INIT = true, you should see:

[SERVER][INIT] server ready: loaded N boards / M editor grants from DB (collision=false)

If loaded 0, the DB is either empty (expected on first run) or the connection failed. The SQL bridge also prints its detection result:

[f5_board:sql_bridge] driver detected: oxmysql

If you don't see that line, check your MySQL resource's logs.

2. Wrong database

If you have multiple databases and the script picked the wrong one, the tables exist but the data is missing. Confirm the active connection in oxmysql settings.

3. Migration error

If you updated the script and a column-add migration failed (very rare — only if the user has insufficient DB privileges), check the IO category:

Config.Debug.categories.IO = true

Drawing Lags / Stutters

Symptom: Drawing strokes feels delayed or jumpy.

1. Network latency

Strokes are batched and sent every StrokeBatchWindowMs (50 ms default). On a high-latency connection, raising the window helps:

config/config.lua
Config.StrokeBatchWindowMs = 100

2. Server-side flood limit hit

A flood of strokes triggers the mutation cooldown (Config.MutationCooldownMs, 150 ms). The client retries silently. If you see consistent lag, the bottleneck might actually be the rendering side, not the network — try lowering Config.Dui.width / height to 768 to reduce the offscreen render cost.

Catalog Shows No Boards At All

Symptom: /board opens, but the grid is empty.

Empty Config.Boards

Most likely you stripped out entries. Re-add at least one:

config/config.lua
Config.Boards = {
{ model = 'prop_cork_board', item = 'corkboard', label = 'ui_board_cork' },
}

Each entry needs all three fields (model, item, label).

"Slow Down — Try Again in a Moment"

Symptom: The catalog refuses to open.

Config.Command.requestCooldownMs (700 ms default) throttles repeated /board opens. If you're testing rapidly, wait 1 s between attempts. To loosen it:

config/config.lua
Config.Command.requestCooldownMs = 200

I See Two Boards in the Same Spot

Symptom: Walking around a placed board shows a second ghost copy.

This usually means the bulk-spawn event raced with a single spawn event. It should self-correct on next sync (~1 s). If it persists, it points to a custom resource that's also spawning entities in the same area. Toggle the SPAWN debug:

config/config.lua
Config.Debug.categories.SPAWN = true

If you see duplicate spawning board N lines for the same id, restart the resource — that's a state desync, not a config issue.

Still Stuck?

  • Enable Config.Debug.enabled = true and Config.Bridge.debug = true. The server console shows what the bridge detected and which path each event takes.
  • Check the client console (F8) for client-side errors.
  • For a permission issue, share the bridge debug output (one line, no PII) on our Discord.
  • Open a support ticket on Discord with: framework name + version, inventory name + version, target name + version, the relevant Config.* block, and the console output of a failing action.

See Also