Skip to main content

FiveM NUI stuck loading: trace the callback before retrying

Written by FiveMCoach · AI-assisted editorial guide; official sources checked

Last updated

FiveM NUI Stuck Loading: Debug the Callback

An evergreen developer guide to diagnosing a stuck NUI action, defining an honest response contract and checking recovery before adding another retry.

Quick answer

Trace one click through the browser handler, NUI request, game-side callback and rendered result. Check which boundary stops responding before changing code. A loading indicator should end in success, a useful rejection or a recoverable error, and a timeout must not be treated as proof that an action never happened.

On this page

Where should you start when a NUI button stays loading?

Write the exact action and expected result before restarting anything. For example: opening a harmless settings panel should load its current display preference and enable the controls. Capture the resource version, reproduction steps and the visible state. Use a development server and test data, especially when the real action affects money, inventory or permissions.

This is evergreen guidance checked on 13 September 2026, with AI-assisted editorial authorship by FiveMCoach. It describes a debugging method, not a newly announced FiveM or framework fix. No FXServer session was run for this article; the small JavaScript helper below is tested separately from the game runtime.

Did the click reach the intended interface?

Separate an input problem from a pending request. Watch whether the browser click handler runs once. If it never runs, inspect the button's disabled state, overlays and the active NUI frame before changing the callback.

Cfx.re documents a focus stack for fullscreen NUI, with the most recently focused resource on top and no click-through across resource frames. It also documents CEF developer tools and the F8 command when developer mode is enabled. Read the fullscreen NUI reference.

During your own controlled test, open the intended frame and compare one click with one handler execution. If a local UI rerender accidentally adds a second listener, fix that lifecycle boundary before testing requests again. Treat this as a possible cause to investigate, not a diagnosis of every stuck interface.

Did the NUI request receive a response?

Compare the browser request's resource name and callback route with the registered handler. Cfx.re's example uses an HTTPS POST to the parent resource and JSON request data. The game-side callback response must be JSON-encodable and returned on every branch, including rejection. A missing response can stall and eventually fail the request. Check the official NUI callback contract.

Create a compact trace for your own code: click received, request dispatched, handler entered, reply produced, result rendered. Record only the boundary and a non-sensitive test reference. Do not log full player records, credentials or private payloads. The first missing boundary tells you where to inspect next; it does not identify the cause by itself.

How do you keep a valid rejection from looking like success?

Choose an application response contract before writing the success screen. For a harmless example, success can carry an explicit boolean and data; rejection can carry a false boolean plus a safe message. Unexpected payloads should produce a recoverable error, not a green confirmation.

This small browser-side classifier is our example contract, not a FiveM API. It assumes the JSON has already been parsed and does not validate a purchase, permission or server-side effect:

function replyState(reply) {
  if (reply?.ok === true) {
    return 'success';
  }
  if (reply?.ok === false) {
    return 'rejected';
  }
  return 'invalid-reply';
}

The helper distinguishes an explicit true, an explicit false and anything else. Its six local checks cover true, false, null, an empty object, a string and a string-valued boolean. They test only this classifier. Your own interface still needs to display the safe message, restore controls appropriately and validate any expected data fields.

Which failures should the browser handle separately?

Fetch does not reject merely because a response has an HTTP error status. Inspect the response status, and handle JSON parsing errors separately from a valid application rejection. An AbortController can cancel the browser request, but that cancellation should not be presented as proof that a downstream operation was rolled back. Review MDN's fetch error and cancellation guidance.

In your UI, use distinct states for idle, submitting, success, rejected and failed. Keep the action label understandable while it is running. On a transport failure, show what the user can do next and preserve safe form input. Avoid swallowing an exception merely to remove the spinner.

If the operation changes persistent state, check the authoritative result before inviting another attempt. Disable repeated clicks while the same request is pending and implement the appropriate duplicate protection at the trusted boundary. A disabled button alone cannot prevent duplicate operations from other clients or retries.

What should a controlled recovery test include?

Test a harmless read or an isolated action first. Exercise an accepted payload, a deliberate application rejection, a missing or malformed reply, and a request that fails to complete within your chosen limit. Confirm that the visible state matches the observed outcome rather than the amount of time that passed.

Then test two rapid clicks, closing the panel while work is pending, reopening it, and stopping the test resource. The desired behavior depends on the action: a read may be safe to repeat, while a transaction needs reconciliation. Write down that rule before making Retry the default response to every error.

If a callback starts a separate server request, trace that boundary independently. A NUI acknowledgement is not sufficient evidence that the server accepted or committed the work. Use the event validation guide for the server-side review and the resource command guide when rehearsing resource lifecycle changes.

What evidence should you keep after the fix?

Save the reproduction steps, the boundary that failed, the correction and the expected versus observed result for each recovery case. Remove temporary verbose logging before release. Repeat the failing case on the intended supported setup; a passing helper test cannot prove that the game's NUI integration works.

For a manageable next milestone, use the free game plan and choose Developer with your current blocker. The developer path explains learning and coaching options if you want help understanding the result. Implementation work has a separate agreed scope.

Checklist
  • Reproduce one action on a controlled setup.
  • Confirm one click reaches the intended handler.
  • Trace dispatch, handler, reply and render.
  • Test accepted, rejected and invalid replies.
  • Preserve input and reconcile uncertain results.
  • Recheck double clicks, close and resource stop.
Symptom Inspect next
No click Focus and overlay
No reply Route and handler
Bad JSON Payload contract
False success Result handling
Repeat action Duplicate protection
Common mistakes

Avoid adding an unconditional success message, retrying a state-changing action blindly, or clearing loading only on the happy path. Do not assume the callback acknowledgement proves a separate server operation finished. Keep diagnostic logs narrow. If a fix changes the reply format, review every caller and rehearse an older or unexpected reply instead of hiding the mismatch.

FiveMCoach perspective

A useful debugging habit is to name the boundary you have actually verified. The click worked, the request replied and the player received the intended result are three different observations. We recommend keeping that distinction in both the developer trace and the player-facing message, so a quiet console or a disappearing spinner does not become a false success claim.

Why can a NUI request remain pending?
One documented cause is a handler branch that does not return its callback response. Also inspect whether the request reached the intended handler. A loading indicator alone cannot identify the failed boundary.
Does a successful HTTP response prove the action worked?
No. Check the application response and, for persistent changes, the authoritative result. Transport success and a completed game or server operation are different checks.
Should I automatically retry every failed NUI action?
No. Decide whether the action is safe to repeat and how uncertain results are reconciled. A read and a state-changing transaction need different recovery rules.
Does the included JavaScript example test FiveM itself?
No. The six local assertions check only the reply classifier. Callback registration, focus, game integration and server-side effects still require a controlled test in the intended FiveM setup.

Ready for the next step?

Stop guessing. Get a concrete plan for your server and move with confidence.

Written by
FiveMCoach · AI-assisted editorial guide; official sources checked
A FiveMCoach contributor responsible for this guide's visible content.