-
Notifications
You must be signed in to change notification settings - Fork 28
Open
Description
Description
After calling disconnect() on a connected BluetoothRemoteGATTServer, the process crashes asynchronously on the next event-loop turn. disconnect() itself does not throw. The error is not catchable from userland because it happens inside the adapter cleanup code and results in an unhandled rejection / process abort.
Reproduction
import { bluetooth } from "webbluetooth";
const SERVICE_UUID = "…"; // any service your peripheral advertises
function nextTick(): Promise<void> {
return new Promise((r) => setTimeout(r, 0));
}
const device = await bluetooth.requestDevice({
filters: [{ services: [SERVICE_UUID] }],
optionalServices: [SERVICE_UUID],
});
console.log("Device:", device.name);
const server = await device.gatt.connect();
console.log("Connected");
server.disconnect();
console.log("Disconnected");
await nextTick(); // crash happens here
console.log("Exit"); // Never reachedExpected behavior
server.disconnect() should disconnect cleanly without throwing later, and the program should continue normally.
Actual behavior
Crash on next event loop turn:
$ node test.js
Device: BleServer
Connected
Disconnected
/tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:78
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
^
TypeError: undefined is not iterable (cannot read property Symbol(Symbol.iterator))
at __values (/tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:78:72)
at PeripheralHandles.deleteHandles (/tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:194:35)
at SimplebleAdapter.<anonymous> (/tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:468:30)
at step (/tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:72:23)
at Object.next (/tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:53:53)
at /tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:47:71
at new Promise (<anonymous>)
at __awaiter (/tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:43:12)
at SimplebleAdapter.disconnect (/tmp/ble-client/node_modules/webbluetooth/dist/adapters/simpleble-adapter.js:457:16)
at BluetoothRemoteGATTServerImpl.disconnect (/tmp/ble-client/node_modules/webbluetooth/dist/server.js:131:28)
Environment
- Node.js 24.13.0
- webbluetooth 3.4.0
- Debian Linux 13
Additional notes
Looks like PeripheralHandles.deleteHandles() iterates over a collection that can be undefined during disconnect cleanup. A guard for missing handle maps (or initializing them consistently) might fix it.
Metadata
Metadata
Assignees
Labels
No labels