What platform are you experiencing this issue on?
Windows x64
What version of UWB are you using?
2.2.8
What Unity version are you running?
6000.3.7f1
Describe what the issue you are experiencing is.
Summary
When calling Application.Quit() (or stopping play mode in the Unity Editor), two
bugs occur together:
- Part A —
NullReferenceException in WebBrowserUIControls.OnDestroy() is
reported as a Unity crash
- Part B — The application hangs for several seconds (or indefinitely) before
finally exiting, caused by WebBrowserClient.Dispose() blocking inside
communicationsManager.Shutdown()
Part A — NullReferenceException in WebBrowserUIControls.OnDestroy
File: Runtime/WebBrowserUIControls.cs, line 46
private void OnDestroy()
{
webBrowserUi.browserClient.OnUrlChanged -= OnUrlChanged; // ← throws NRE
}
webBrowserUi or webBrowserUi.browserClient is null or refers to a destroyed
Unity native object at the time OnDestroy() is called. Unity does not guarantee
the order in which OnDestroy() is called across components, even on the same
GameObject. If WebBrowserUIBasic has already been torn down before
WebBrowserUIControls.OnDestroy() runs, the reference is invalid.
Error logged:
NullReferenceException: Object reference not set to an instance of an object
at VoltstroStudios.UnityWebBrowser.WebBrowserUIControls.OnDestroy ()
Unity reports this as a crash and attempts to upload a crash report.
Proposed fix (WebBrowserUIControls.cs line 44–47):
private void OnDestroy()
{
if (webBrowserUi != null && webBrowserUi.browserClient != null)
webBrowserUi.browserClient.OnUrlChanged -= OnUrlChanged;
}
Part B — Application.Quit hangs in WebBrowserClient.Dispose
File: Runtime/Core/WebBrowserClient.cs, around line 1190
WebBrowserClient.Dispose() calls communicationsManager.Shutdown() before
killing the engine process. communicationsManager.Shutdown() calls
engineProxy.Shutdown() which is a blocking RPC call that waits for the CEF
browser engine process to respond and exit cleanly. CEF shutdown can be slow (it
spawns multiple child processes), causing the Unity application to hang for several
seconds or indefinitely on exit.
The engineProcess.KillProcess() call that would resolve the hang is placed
after the blocking call and is therefore never reached in time:
// Current order in Dispose() — causes hang:
communicationsManager.Shutdown(); // ← blocks here waiting for CEF
communicationsManager?.Dispose();
if (!engineProcess.HasExited)
engineProcess.KillProcess(); // ← never reached promptly
Proposed fix — kill the engine process first, then attempt graceful shutdown
(which will now fail fast on a broken pipe, caught by the existing try/catch):
// Fixed order — kill first, then cleanup:
if (engineProcess != null && !engineProcess.HasExited)
engineProcess.KillProcess(); // terminate CEF immediately
try
{
if (ReadySignalReceived && IsConnected)
communicationsManager.Shutdown(); // fails fast, exception caught below
}
catch (Exception ex)
{
logger.Error($"Some error occured while shutting down the engine! {ex}");
}
communicationsManager?.Dispose();
if (engineProcess != null)
{
engineProcess.Dispose();
engineProcess = null;
}
This matches the behaviour of WindowProcess.KillProcess() which already uses
TerminateJobObject — a hard, immediate termination — so the intent is clearly
to force-terminate when disposing.
Provide reproducible steps for this issue.
- Add
WebBrowserUIBasic and WebBrowserUIControls to a scene
- Call
Application.Quit() (or stop play mode in the Editor)
- Part A: Observe
NullReferenceException crash report in Player.log
- Part B: Observe application hangs for several seconds before exiting
Any additional info you like to provide?
Temporary Workaround
Part A — no active workaround.
The NRE still occurs in WebBrowserUIControls.OnDestroy() during Unity's normal
teardown sweep and appears in Player.log as Failed to upload Crash Report to Cloud Diagnostics. (the upload fails fast because Unity services are already
partially torn down at that point). This is cosmetic — it does not cause a hang
or affect functionality. An earlier attempt to suppress it via DestroyImmediate
in OnApplicationQuit() was abandoned: it fired the NRE while the network stack
was still fully up, causing the crash report to upload successfully and block exit
for several seconds. The upstream null-guard fix (above) is the correct resolution.
Part B — working workaround: EmbeddedBrowserController.ForceShutdown()
Called from MonoBehaviour.OnApplicationQuit() (fires before any OnDestroy()),
this uses reflection to reach WebBrowserClient.engineProcess.KillProcess() and
terminate the CEF browser process immediately. With the process already dead,
communicationsManager.Shutdown() hits a broken pipe and fails fast (exception
caught by UWB's own try/catch inside Dispose()), so teardown completes in
milliseconds. The [UWB]: Some error occured while shutting down the engine! log
lines are expected and benign.
For now, the workaround for Part B is an acceptable option, though slightly messy due to additional errors to log!
What platform are you experiencing this issue on?
Windows x64
What version of UWB are you using?
2.2.8
What Unity version are you running?
6000.3.7f1
Describe what the issue you are experiencing is.
Summary
When calling
Application.Quit()(or stopping play mode in the Unity Editor), twobugs occur together:
NullReferenceExceptioninWebBrowserUIControls.OnDestroy()isreported as a Unity crash
finally exiting, caused by
WebBrowserClient.Dispose()blocking insidecommunicationsManager.Shutdown()Part A — NullReferenceException in WebBrowserUIControls.OnDestroy
File:
Runtime/WebBrowserUIControls.cs, line 46webBrowserUiorwebBrowserUi.browserClientis null or refers to a destroyedUnity native object at the time
OnDestroy()is called. Unity does not guaranteethe order in which
OnDestroy()is called across components, even on the sameGameObject. If
WebBrowserUIBasichas already been torn down beforeWebBrowserUIControls.OnDestroy()runs, the reference is invalid.Error logged:
Unity reports this as a crash and attempts to upload a crash report.
Proposed fix (
WebBrowserUIControls.csline 44–47):Part B — Application.Quit hangs in WebBrowserClient.Dispose
File:
Runtime/Core/WebBrowserClient.cs, around line 1190WebBrowserClient.Dispose()callscommunicationsManager.Shutdown()beforekilling the engine process.
communicationsManager.Shutdown()callsengineProxy.Shutdown()which is a blocking RPC call that waits for the CEFbrowser engine process to respond and exit cleanly. CEF shutdown can be slow (it
spawns multiple child processes), causing the Unity application to hang for several
seconds or indefinitely on exit.
The
engineProcess.KillProcess()call that would resolve the hang is placedafter the blocking call and is therefore never reached in time:
Proposed fix — kill the engine process first, then attempt graceful shutdown
(which will now fail fast on a broken pipe, caught by the existing try/catch):
This matches the behaviour of
WindowProcess.KillProcess()which already usesTerminateJobObject— a hard, immediate termination — so the intent is clearlyto force-terminate when disposing.
Provide reproducible steps for this issue.
WebBrowserUIBasicandWebBrowserUIControlsto a sceneApplication.Quit()(or stop play mode in the Editor)NullReferenceExceptioncrash report inPlayer.logAny additional info you like to provide?
Temporary Workaround
Part A — no active workaround.
The NRE still occurs in
WebBrowserUIControls.OnDestroy()during Unity's normalteardown sweep and appears in
Player.logasFailed to upload Crash Report to Cloud Diagnostics.(the upload fails fast because Unity services are alreadypartially torn down at that point). This is cosmetic — it does not cause a hang
or affect functionality. An earlier attempt to suppress it via
DestroyImmediatein
OnApplicationQuit()was abandoned: it fired the NRE while the network stackwas still fully up, causing the crash report to upload successfully and block exit
for several seconds. The upstream null-guard fix (above) is the correct resolution.
Part B — working workaround:
EmbeddedBrowserController.ForceShutdown()Called from
MonoBehaviour.OnApplicationQuit()(fires before anyOnDestroy()),this uses reflection to reach
WebBrowserClient.engineProcess.KillProcess()andterminate the CEF browser process immediately. With the process already dead,
communicationsManager.Shutdown()hits a broken pipe and fails fast (exceptioncaught by UWB's own try/catch inside
Dispose()), so teardown completes inmilliseconds. The
[UWB]: Some error occured while shutting down the engine!loglines are expected and benign.
For now, the workaround for Part B is an acceptable option, though slightly messy due to additional errors to log!