Description
When communicating with the background daemon over IPC, DaemonIpcClient.request adds the request promise to a pending map and then calls socket.write(). If the socket is already closed or in an error state, write() throws synchronously. Because there is no try/catch, the promise is never resolved/rejected and the slot leaks in the map forever.
Environment
- OS: Any
- Node version: Node 18+
- Nanocoder version: 1.30.0
Steps to Reproduce
- Force a daemon crash or close the IPC socket prematurely.
- Attempt an IPC request right as the socket closes.
write() throws, and the pending promise sits in memory forever.
Expected Behavior
If write() fails synchronously, the promise should be rejected and removed from the pending map.
Actual Behavior
The throw bypasses the promise resolution, leaking the map entry.
Additional Context
Implementation Notes
Wrap this.socket?.write() in a try/catch in source/daemon/ipc.ts:248-251. In the catch block, call reject(error) and this.pending.delete(id).
Description
When communicating with the background daemon over IPC,
DaemonIpcClient.requestadds the request promise to a pending map and then callssocket.write(). If the socket is already closed or in an error state,write()throws synchronously. Because there is notry/catch, the promise is never resolved/rejected and the slot leaks in the map forever.Environment
Steps to Reproduce
write()throws, and the pending promise sits in memory forever.Expected Behavior
If
write()fails synchronously, the promise should be rejected and removed from thependingmap.Actual Behavior
The throw bypasses the promise resolution, leaking the map entry.
Additional Context
Implementation Notes
Wrap
this.socket?.write()in atry/catchinsource/daemon/ipc.ts:248-251. In thecatchblock, callreject(error)andthis.pending.delete(id).