[BUG] v1.0.3: "Object has been destroyed" error dialog on quit (Windows)
What version of eigent are you using?
1.0.3
System information
Eigent v1.0.3 — "A JavaScript error occurred in the main process" (TypeError: Object has been destroyed) when quitting
Summary
Quitting Eigent v1.0.3 on Windows reliably shows an Electron error dialog:
A JavaScript error occurred in the main process — Uncaught Exception: TypeError: Object has been destroyed.
The app exits correctly afterwards (cleanup completes), so this is cosmetic but very visible — it appears on every quit.
Environment
- Eigent v1.0.3 (latest, released 2026-08-28), Windows 11 (also reproduced on Windows 10-class hardware), x64
- Occurs on a fresh install as well as after upgrade from v1.0.2
Steps to reproduce
- Start Eigent v1.0.3, log in, wait for the UI to load.
- Quit the app (window close / Quit).
- The error dialog appears; clicking OK finishes the quit.
Stack trace (from the dialog)
TypeError: Object has been destroyed
at Dd.unbindHealthListeners (dist-electron:115)
at Dd.unbindWindow (dist-electron:76)
at App.<anonymous> (dist-electron:74)
at App.emit (node:events:530:35)The same error also appears via the IPC quit path (ipcMainImpl.emit → Dd.quit → unbindWindow).
Root cause analysis
In unbindHealthListeners(e) the code accesses e.webContents (e.g. e.webContents.off("did-start-loading", …)) without checking whether the BrowserWindow / its webContents are already destroyed:
unbindHealthListeners(e) {
e.off("unresponsive", this.handleRendererUnresponsive),
e.off("responsive", this.handleRendererResponsive),
e.webContents.off("did-start-loading", this.handleRendererLoading), // <- throws if destroyed
e.webContents.off("render-process-gone", this.handleRendererGone),
e.webContents.off("destroyed", this.handleRendererDestroyed);
}
unbindWindow() {
this.window && (this.window.off("close", this.handleWindowClose), this.unbindHealthListeners(this.window)), // <- no isDestroyed() guard
...
}During quit the renderer is already closed/destroyed, so the webContents getter on the destroyed BrowserWindow throws TypeError: Object has been destroyed before any listeners are removed. unbindWindow() is also missing an isDestroyed() check. Note that handleWindowClose and sendRequest in the same class do guard with isDestroyed() — this cleanup path was simply missed.
Suggested fix
Guard both places, consistent with the rest of the class:
unbindHealthListeners(e) {
e.off("unresponsive", this.handleRendererUnresponsive),
e.off("responsive", this.handleRendererResponsive);
if (e.webContents && !e.webContents.isDestroyed()) {
e.webContents.off("did-start-loading", this.handleRendererLoading),
e.webContents.off("render-process-gone", this.handleRendererGone),
e.webContents.off("destroyed", this.handleRendererDestroyed);
}
}
unbindWindow() {
if (this.window && !this.window.isDestroyed()) {
this.window.off("close", this.handleWindowClose);
this.unbindHealthListeners(this.window);
}
...
}Impact
- No data loss, no hang — the app quits cleanly after OK.
- Triggers on every quit and additionally as a follow-up crash whenever the backend fails at startup (the cleanup path after a backend error hits the same bug).
- v1.0.2 did not show this error; it is a v1.0.3 regression.
Problem description
Eigent v1.0.3 — "A JavaScript error occurred in the main process" (TypeError: Object has been destroyed) when quitting
Summary
Quitting Eigent v1.0.3 on Windows reliably shows an Electron error dialog:
A JavaScript error occurred in the main process — Uncaught Exception: TypeError: Object has been destroyed.
The app exits correctly afterwards (cleanup completes), so this is cosmetic but very visible — it appears on every quit.
Environment
- Eigent v1.0.3 (latest, released 2026-08-28), Windows 11 (also reproduced on Windows 10-class hardware), x64
- Occurs on a fresh install as well as after upgrade from v1.0.2
Steps to reproduce
- Start Eigent v1.0.3, log in, wait for the UI to load.
- Quit the app (window close / Quit).
- The error dialog appears; clicking OK finishes the quit.
Stack trace (from the dialog)
TypeError: Object has been destroyed
at Dd.unbindHealthListeners (dist-electron:115)
at Dd.unbindWindow (dist-electron:76)
at App.<anonymous> (dist-electron:74)
at App.emit (node:events:530:35)The same error also appears via the IPC quit path (ipcMainImpl.emit → Dd.quit → unbindWindow).
Root cause analysis
In unbindHealthListeners(e) the code accesses e.webContents (e.g. e.webContents.off("did-start-loading", …)) without checking whether the BrowserWindow / its webContents are already destroyed:
unbindHealthListeners(e) {
e.off("unresponsive", this.handleRendererUnresponsive),
e.off("responsive", this.handleRendererResponsive),
e.webContents.off("did-start-loading", this.handleRendererLoading), // <- throws if destroyed
e.webContents.off("render-process-gone", this.handleRendererGone),
e.webContents.off("destroyed", this.handleRendererDestroyed);
}
unbindWindow() {
this.window && (this.window.off("close", this.handleWindowClose), this.unbindHealthListeners(this.window)), // <- no isDestroyed() guard
...
}During quit the renderer is already closed/destroyed, so the webContents getter on the destroyed BrowserWindow throws TypeError: Object has been destroyed before any listeners are removed. unbindWindow() is also missing an isDestroyed() check. Note that handleWindowClose and sendRequest in the same class do guard with isDestroyed() — this cleanup path was simply missed.
Suggested fix
Guard both places, consistent with the rest of the class:
unbindHealthListeners(e) {
e.off("unresponsive", this.handleRendererUnresponsive),
e.off("responsive", this.handleRendererResponsive);
if (e.webContents && !e.webContents.isDestroyed()) {
e.webContents.off("did-start-loading", this.handleRendererLoading),
e.webContents.off("render-process-gone", this.handleRendererGone),
e.webContents.off("destroyed", this.handleRendererDestroyed);
}
}
unbindWindow() {
if (this.window && !this.window.isDestroyed()) {
this.window.off("close", this.handleWindowClose);
this.unbindHealthListeners(this.window);
}
...
}Impact
- No data loss, no hang — the app quits cleanly after OK.
- Triggers on every quit and additionally as a follow-up crash whenever the backend fails at startup (the cleanup path after a backend error hits the same bug).
- v1.0.2 did not show this error; it is a v1.0.3 regression.
log
https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:23:16,580 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [info] BACKEND: 2026-09-01 12:23:39,830 - toolkit_listen - INFO - [TOOLKIT DEACTIVATE] Toolkit: Terminal Toolkit | Method: shell exec | Task ID: 1788257969813-1994 | Agent: Agents.single_agent | Status: SUCCESS | Timestamp: 2026-09-01T12:23:39.830014 [info] BACKEND: 2026-09-01 12:23:40,336 - agent - INFO - Agent Agents.single_agent executing async tool: write_to_file from toolkit: File Toolkit with args: {"title": "Self-check probe", "content": "Eigent self-check: file write succeeded.", "filename": "__selfcheck_probe.txt", "encoding": "utf-8", "use_latex": false, "message_title": null, "message_description": null, "message_attachment": null} [error] BACKEND: 2026-09-01 12:23:44,233 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:23:45,332 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:23:45,937 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [info] BACKEND: 2026-09-01 12:23:45,937 - toolkit_listen - INFO - [TOOLKIT DEACTIVATE] Toolkit: File Toolkit | Method: write to file | Task ID: 1788257969813-1994 | Agent: Agents.single_agent | Status: SUCCESS | Timestamp: 2026-09-01T12:23:45.937400 [info] BACKEND: 2026-09-01 12:23:46,014 - agent - INFO - Agent Agents.single_agent executing async tool: agent_run_subagent from toolkit: AgentToolkit with args: {"prompt": "Führe eine minimale Selbstprüfung aus: Antworte nur mit 'Subagent OK' und einem kurzen Satz, ob du die Aufgabe korrekt empfangen konntest. Keine Dateien verändern und keine weiteren Agenten starten.", "description": "Orchestrierungs-Selbsttest", "subagent_type": "general-purpose", "agent_id": null, "wait": true, "timeout": 30} [error] BACKEND: 2026-09-01 12:23:46,497 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:23:50,931 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:23:51,462 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:23:51,979 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:23:52,845 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:24:10,281 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:24:10,994 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [info] BACKEND: 2026-09-01 12:24:27,267 - agent - INFO - Agent Agents.single_agent executing async tool: step_update from toolkit: TodoToolkit with args: {"plan_item_id": "pli_9be33418917245a1846dfb3944036bf0", "summary": "Kernfunktionen sind einsatzfähig: Befehlsausführung, Python, Node.js, Git, Datei-Schreibzugriff und Agent-Orchestrierung funktionieren. Zwei anfängliche Testbefehle scheiterten nur an der verwendeten Shell-Syntax bzw. am vorgesehenen Safe-Mode."} [info] BACKEND: 2026-09-01 12:24:32,402 - agent - INFO - Agent Agents.single_agent executing async tool: shell_exec from toolkit: Terminal Toolkit with args: {"id": "selfcheck-cleanup", "command": "if exist __selfcheck_probe.txt del __selfcheck_probe.txt && if exist terminal_logs rmdir /s /q terminal_logs && git status --short --branch", "block": true, "timeout": 30, "message_title": null, "message_description": null, "message_attachment": null} [error] BACKEND: 2026-09-01 12:24:32,845 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:24:33,311 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:24:33,857 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:24:37,821 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:24:38,321 - sync_step - ERROR - Failed to sync step to https://dev.eigent.ai/api/v1/chat/steps: ConnectTimeout: [error] BACKEND: 2026-09-01 12:24:46,191 - toolkit_listen - INFO - [TOOLKIT DEACTIVATE] Toolkit: Terminal Toolkit | Method: shell exec | Task ID: 1788257969813-1994 | Agent: Agents.single_agent | Status: ERROR | Timestamp: 2026-09-01T12:24:46.191591 [error] BACKEND: 2026-09-01 12:24:46,440 - agent - ERROR - Agent Agents.single_agent unexpected error in async step: tool 'shell_exec' may have produced an external side effect Traceback (most recent call last): File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\function_tool.py", line 630, in call result = self.func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\message_integration.py", line 223, in bound_method_wrapper return enhanced_func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\message_integration.py", line 466, in wrapper result = func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\\utils\listen\toolkit_listen.py", line 432, in sync_wrapper raise error File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\\utils\listen\toolkit_listen.py", line 396, in sync_wrapper res = func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\toolkit\terminal_toolkit.py", line 758, in shell_exec return self._shell_exec_with_workspace_checkpoint( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\toolkit\terminal_toolkit.py", line 846, in _shell_exec_with_workspace_checkpoint result = super().shell_exec( ^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\terminal_toolkit\terminal_toolkit.py", line 901, in shell_exec self._write_to_log(self.blocking_log_file, log_entry + "\n") File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\\utils\commons.py", line 1062, in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\toolkit\terminal_toolkit.py", line 708, in _write_to_log super()._write_to_log(log_file, content) File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\\utils\commons.py", line 1062, in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\terminal_toolkit\terminal_toolkit.py", line 486, in _write_to_log with open(log_file, "a", encoding="utf-8") as f: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ FileNotFoundError: [Errno 2] No such file or directory: 'C:\Users\JMH\eigent\\user_45743\space_73ed35f53877480b8697baa78e638522\terminal_logs\blocking_commands.log'
During handling of the above exception, another exception occurred:
Traceback (most recent call last): File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\listen_chat_agent.py", line 1357, in _aexecute_tool result = await asyncio.to_thread(tool, **args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\prebuilt\\uv_python\cpython-3.11.11-windows-x86_64-none\Lib\asyncio\threads.py", line 25, in to_thread return await loop.run_in_executor(None, func_call) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\prebuilt\\uv_python\cpython-3.11.11-windows-x86_64-none\Lib\concurrent\futures\thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\function_tool.py", line 638, in call raise ValueError( ValueError: Execution of function shell_exec failed with kwargs={'id': 'selfcheck-cleanup', 'command': 'if exist __selfcheck_probe.txt del __selfcheck_probe.txt && if exist terminal_logs rmdir /s /q terminal_logs && git status --short --branch', 'block': True, 'timeout': 30, 'message_title': None, 'message_description': None, 'message_attachment': None}. Error: [Errno 2] No such file or directory: 'C:\Users\JMH\eigent\\user_45743\space_73ed35f53877480b8697baa78e638522\terminal_logs\blocking_commands.log'
The above exception was the direct cause of the following exception:
Traceback (most recent call last): File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\listen_chat_agent.py", line 929, in astep res = await self._astep_with_active_timeout( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\listen_chat_agent.py", line 404, in _astep_with_active_timeout return await super()._astep_non_streaming_task( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\agents\chat_agent.py", line 3346, in _astep_non_streaming_task tool_call_record = await self._aexecute_tool( ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\listen_chat_agent.py", line 1404, in _aexecute_tool await asyncio.to_thread( File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\prebuilt\\uv_python\cpython-3.11.11-windows-x86_64-none\Lib\concurrent\futures\thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\run_runtime\tool_checkpoint.py", line 1037, in finish_tool_checkpoint raise UnsafeToolOutcomeError( app.run_runtime.tool_checkpoint.UnsafeToolOutcomeError: tool 'shell_exec' may have produced an external side effect [error] BACKEND: 2026-09-01 12:24:47,451 - single_agent_service - ERROR - Single Agent turn failed Traceback (most recent call last): File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\function_tool.py", line 630, in call result = self.func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\message_integration.py", line 223, in bound_method_wrapper return enhanced_func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\message_integration.py", line 466, in wrapper result = func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\\utils\listen\toolkit_listen.py", line 432, in sync_wrapper raise error File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\\utils\listen\toolkit_listen.py", line 396, in sync_wrapper res = func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\toolkit\terminal_toolkit.py", line 758, in shell_exec return self._shell_exec_with_workspace_checkpoint( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\toolkit\terminal_toolkit.py", line 846, in _shell_exec_with_workspace_checkpoint result = super().shell_exec( ^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\terminal_toolkit\terminal_toolkit.py", line 901, in shell_exec self._write_to_log(self.blocking_log_file, log_entry + "\n") File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\\utils\commons.py", line 1062, in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH\AppData\Local\Programs\Eigent\resources\backend\app\agent\toolkit\terminal_toolkit.py", line 708, in _write_to_log super()._write_to_log(log_file, content) File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\\utils\commons.py", line 1062, in wrapper return func(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\JMH.eigent\venvs\backend-1.0.3\Lib\site-packages\camel\toolkits\terminal_toolkit\terminal_toolkit.py", line 486, in _write_to_log with o
Source: eigent-ai/eigent