Problem
findAvailablePort synchronously creates a net.Server, calls server.listen(port, ...) with a callback, and immediately returns the port without waiting for the callback to fire. On a system where the port is already in use, listen fires an error asynchronously that the function never observes, but the function already returned that port. OSC service initialize() then hands the unverified port to osc.UDPPort({ localPort: this.localPort, ... }) which either quietly fails to bind, or worse, replaces whatever was listening on that port (if the kernel lets UDP and TCP collide).
Evidence
main/services/oscService.ts:401-410
findAvailablePort(startPort: number, endPort: number): number {
const net = require('net')
for (let port = startPort; port <= endPort; port++) {
try {
const server = net.createServer()
server.listen(port, () => {
server.close()
})
return port
} catch (_error) { continue }
}
return startPort
}
File: main/services/oscService.ts:401 in ComfyChloe/ARC-Client.
Suggested fix
Make this an async helper that wraps listen in a Promise, attaches both listening (close immediately and resolve the port) and error (reject) handlers, and falls through to the next port on EADDRINUSE. The current pattern only catches synchronous throws, not the async EADDRINUSE case.
Problem
findAvailablePortsynchronously creates anet.Server, callsserver.listen(port, ...)with a callback, and immediately returns the port without waiting for the callback to fire. On a system where the port is already in use,listenfires an error asynchronously that the function never observes, but the function already returned that port.OSC service initialize()then hands the unverified port toosc.UDPPort({ localPort: this.localPort, ... })which either quietly fails to bind, or worse, replaces whatever was listening on that port (if the kernel lets UDP and TCP collide).Evidence
File:
main/services/oscService.ts:401inComfyChloe/ARC-Client.Suggested fix
Make this an
asynchelper that wrapslistenin a Promise, attaches bothlistening(close immediately and resolve the port) anderror(reject) handlers, and falls through to the next port onEADDRINUSE. The current pattern only catches synchronous throws, not the asyncEADDRINUSEcase.