Acknowledged
CIQQA-4568

Venu 3S 17.05 RTL Trap with CONNECTION_STRATEGY_SECURE_PAIR_BOND

Issue

BluetoothLowEnergy.CONNECTION_STRATEGY_SECURE_PAIR_BOND followed by BluetoothLowEnergy.pairDevice() reproducibly causes a native watch restart while connecting to a PIN-disabled Meshtastic BLE peripheral.

I reduced this to a standalone app with only the BluetoothLowEnergy permission. It contains no production UI, storage, protobuf parsing, Sensor API integration, timers, communications permission, or third-party barrel.

The default-strategy control connects successfully. An otherwise identical build that selects CONNECTION_STRATEGY_SECURE_PAIR_BOND restarts the entire watch before the connected callback is delivered.

Environment

  • Device: Garmin Venu 3S
  • Part number: 006-B4261-00
  • Firmware: 17.05
  • Connect IQ version: 6.0
  • Connect IQ SDK: 9.2.0
  • Build OS: Ubuntu 24.04
  • Development tool: monkeyc command line
  • VS Code and extension: Not applicable
  • App type: Watch app
  • Manifest minimum API: 5.1.0
  • Peripheral: Meshtastic BLE radio with PIN disabled
  • Peripheral service UUID: 6ba1b218-15a8-461f-9fa8-5dcae273eafd

Minimal Application Behaviour

The standalone application:

  1. Registers the Meshtastic BLE service and its three characteristics.
  2. Scans for advertisements containing the service UUID.
  3. Uses a fresh ScanResult received by onScanResults().
  4. Stops scanning before pairing.
  5. Retains the fresh ScanResult.
  6. Retains the Device returned by pairDevice().
  7. Waits for onConnectedStateChanged().
  8. Performs no characteristic or descriptor I/O.

This follows the object-lifetime pattern used by Garmin's NordicThingy52 sample and rules out stale ScanResult or prematurely collected Device objects.

Controlled A/B Result

I built two variants from the same source. Their only behavioural difference is the selected connection strategy.

Default-Strategy Control

The default-strategy build connects successfully:

REPRO: app-start used=8760 free=773232 total=781992
REPRO: connection-strategy=default
REPRO: profile-registered-call-returned
REPRO: scan-started
REPRO: match name=null rssi=-49
REPRO: scan-stop-call-returned
REPRO: pairDevice-returned device=non-null
REPRO: connected-state=1 isConnected=true
REPRO: app-stop

The control produced no new native error or watch restart. This rules out a general pairDevice() failure on this device and firmware.

Secure-Strategy Variant

The secure build changes only one behaviour. Before registering the profile and starting the scan, it calls:

BluetoothLowEnergy.setConnectionStrategy(
    BluetoothLowEnergy.CONNECTION_STRATEGY_SECURE_PAIR_BOND
);

The application finds the same peripheral, stops scanning, retains the fresh ScanResult, and retains the non-null Device returned by pairDevice(). The entire watch then restarts before onConnectedStateChanged(CONNECTION_STATE_CONNECTED) is delivered.

Reproduction Steps

  1. Configure a Meshtastic radio with Bluetooth enabled and pairing mode set to No PIN.
  2. Disconnect any phone or other BLE central from the radio.
  3. Place the radio within one metre of the Venu 3S.
  4. Install and launch the attached secure BLE Pair Repro watch app.
  5. The app discovers the service, stops scanning, and calls pairDevice().
  6. pairDevice() returns a non-null Device.
  7. The entire watch restarts before the connected-state callback is delivered.

Native Error

error_cause: RTL Trap
RTL Error Number: 0x037
program counter: 0x10001491
page stack depth: 3
page stack: 1028,1127,1030

The secure application's pre-created Connect IQ log remains empty because the firmware restarts before its output is flushed. A redacted Garmin native error record is attached.

Available memory immediately before BLE setup is approximately 773 KB, so this is not a Connect IQ out-of-memory exception.

Expected Behaviour

The secure strategy should establish the secure connection, report a failure through a documented exception or BLE callback/status, or report that the requested strategy is unsupported.

Calling a public Connect IQ API must not cause a native RTL trap and restart the entire watch.

Attachments

  • venu3s-pairdevice-repro-source.zip: complete minimal source for both default and secure variants, excluding generated binaries.
  • default-control-success.txt: complete successful control trace.
  • secure-strategy-native-error-redacted.txt: native Venu 3S error record with the unique unit ID removed.

I can provide the complete native error record and Garmin-generated RAM dump through a private channel if required. I have not attached the RAM dump publicly because it may contain device-identifying or runtime data.

Related Reports

venu3s-pairdevice-repro-source.zip

REPRO: app-start used=8760 free=773232 total=781992
REPRO: connection-strategy=default
REPRO: profile-registered-call-returned
REPRO: scan-started
REPRO: match name=null rssi=-49
REPRO: scan-stop-call-returned
REPRO: pairDevice-returned device=non-null
REPRO: connected-state=1 isConnected=true
REPRO: app-stop
[
  {
    "unit_id": "REDACTED",
    "product_name": "Venu 3S",
    "software_part_number": "006-B4261-00",
    "ms_since_epoch": "1783960840000",
    "system_version": "17.05",
    "build_type": "Production",
    "backtrace": "0x100013f1\n\t0x1000116b\n\t0x10009fcd\n\t0x181fce73\n\t0x100010e1\n\t0x10000003\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x10000007\n\t0x10000003\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t0x1000000f\n\t",
    "error_cause": "RTL Trap",
    "proprietary_info": {
      "Commit ID": "03cc5699e48b7e90c6414fcc4ec45cdd70cfd780",
      "Time": "2026-7-13 16:40:40",
      "uptime": "63078085",
      "pageStackDepth": "3",
      "pageStack": "1028,1127,1030",
      "RTL Error Number": "0x037",
      "rtl_reg": "r[0]: 0x303223f1\n\tr[1]: 0x30322734\n\tr[2]: 0x00000001\n\tr[3]: 0x00000000\n\tr[4]: 0x303223f1\n\tr[5]: 0x00000001\n\tr[6]: 0x00000001\n\tr[7]: 0x30322378\n\tr[8]: 0x00000001\n\tr[9]: 0x3033897c\n\tr[10]: 0x304a9320\n\tr[11]: 0x000000ff\n\tr[12]: 0x10009fcd\n\tr[13]: 0x30322358\n\tr[14]: 0x181fce73\n\tr[15]: 0x00000000\n\tr[16]: 0x60100000\n\tr[17]: 0x00000000\n\tr[18]: 0x00020000\n\tr[19]: 0xe000ed38\n\tr[20]: 0xe000ed34\n\tr[21]: 0x00000000\n\tr[22]: 0x303222f0\n\t",
      "programCounter": "0x10001491",
      "stackPointer": "0x303ae9b8"
    }
  }
]