Skip to content

Include disconnect status in NotConnectedException#1216

Draft
twyatt wants to merge 1 commit into
mainfrom
cursor/not-connected-exception-status-1e19
Draft

Include disconnect status in NotConnectedException#1216
twyatt wants to merge 1 commit into
mainfrom
cursor/not-connected-exception-status-1e19

Conversation

@twyatt

@twyatt twyatt commented Jul 16, 2026

Copy link
Copy Markdown
Member

Closes #1154

Summary

Adds a status: State.Disconnected.Status? property to NotConnectedException, so clients can examine the underlying cause of a connection failure (e.g. Android GATT status) directly from the exception, rather than having to separately monitor State.Disconnected (which can be racy, or masked by a downstream symptom such as a GattStatusException from a failed requestMtu, as described in #1154).

public open class NotConnectedException(
    message: String? = null,
    cause: Throwable? = null,
    public val status: State.Disconnected.Status? = null,
) : IOException(message, cause)

status is null when unavailable (e.g. disconnect was requested, or the underlying platform did not provide a status).

Where status is populated

  • Android
    • Callback.onConnectionStateChange: the GATT status (translated via the existing disconnectedConnectionStatus mapping) is included in the NotConnectedException used to close the response channel — this is the location referenced in Include disconnectedConnectionStatus in NotConnectedException #1154.
    • Connection: "Disconnect detected" disposal includes State.Disconnected.status.
    • BluetoothDeviceAndroidPeripheral.connectionOrThrow: includes the status of the current Disconnected state (if applicable).
  • Apple
    • Connection: "Disconnect detected" disposal includes State.Disconnected.status (translated from CBError via the existing NSError.toStatus() mapping).
    • PeripheralDelegate.close: propagates the status from the causing NotConnectedException (if any) when closing the response channel.
    • CBPeripheralCoreBluetoothPeripheral.connectionOrThrow: includes the status of the current Disconnected state (if applicable).
  • Common
    • Peripheral.suspendUntilOrThrow: includes State.Disconnected.status (e.g. connection dropped while establishing a connection).

JavaScript/Web is unchanged, as State.Disconnected.status is always null on that platform. JVM (btleplug) is unchanged, as no disconnect status is available from the underlying callback.

API / binary compatibility

Since the new constructor parameter has a default value, this change is source compatible but not binary compatible (the two-arg <init>(String, Throwable) JVM constructor is replaced by a three-arg constructor). The api/jvm and api/android dumps have been updated accordingly.

Note

./gradlew :kable-core:apiDump only regenerated the api/jvm dump on my machine (no BCV dump task appears to be registered for the android target under AGP 9.3 / BCV 0.18.1 — possibly related: api/android/kable-core.api was left untouched by #1197 and still lags the JVM dump), so the api/android dump portion of this change was updated manually to match.

Testing

  • Added CallbackTests (Robolectric, androidHostTest) verifying that onConnectionStateChange closes the response channel with a NotConnectedException carrying:
  • ./gradlew :kable-core:apiCheck :kable-core:lintKotlin :kable-core:jvmTest :kable-core:testAndroidHostTest passes locally (Linux; Apple targets compile-verified by CI only, as they are excluded from non-macOS builds).
Open in Web Open in Cursor 

Adds a 'status' property ('State.Disconnected.Status?') to
'NotConnectedException', allowing clients to examine the underlying
cause of a connection failure (e.g. Android GATT status) directly from
the exception, rather than having to separately monitor the
'State.Disconnected' state.

The status is populated wherever it is available:
- Android: 'onConnectionStateChange' GATT status when closing the
  response channel, and 'State.Disconnected.status' when a disconnect
  is detected or an I/O operation is attempted without a connection.
- Apple: 'State.Disconnected.status' when a disconnect is detected or
  an I/O operation is attempted without a connection; status is
  propagated when the peripheral delegate is closed.
- Common: 'State.Disconnected.status' when suspending until a
  connection state is reached.

Closes #1154

Co-authored-by: Travis Wyatt <travis.i.wyatt@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Include disconnectedConnectionStatus in NotConnectedException

2 participants