Acknowledged
CIQQA-4776

Venu 4 (fw 18.32) — RTL Trap / full watch reset when ending an ActivityRecording session (Session.stop() + Session.save())

Summary

On Venu 4 - 45mm, firmware 18.32, a Connect IQ watch-app that records an ActivityRecording session reliably causes a native RTL Trap that reboots the entire watch when the session is ended (stop() followed by save()). End users also report the app being closed and a native activity (e.g. "Running") being launched instead.

The crash is deterministic: three captured native error records are byte-for-byte identical in backtrace, program counter and register state, even though the device uptime at crash varied from ~17 minutes to ~18 hours. Free memory is high, so this is not a Connect IQ out-of-memory condition.

This mirrors an already-acknowledged class of Venu RTL Traps where a public CIQ API call causes a native trap / watch restart (e.g. CIQQA-4568, Venu 3S 17.05).

Device / environment

  • Product: Venu 4 - 45mm
  • Software part number: 006-B4643-00
  • System version (firmware): 18.32
  • Unit id: 3619146388
  • App type: watch-app, records one ActivityRecording session (Activity.SPORT_TRAINING), communicates with a phone companion via Communications (direct messaging + makeWebRequest to a local companion).

Steps to reproduce

  1. Launch the app; it starts an ActivityRecording session (SPORT_TRAINING).
  2. Let it run (time to crash varies — see uptimes below; not time-dependent).
  3. End the workout, which runs Session.stop() then Session.save().
  4. The watch either reboots (RTL Trap) or closes the app and launches a native activity.

Expected behaviour

Session.stop() / Session.save() are public documented APIs that return a Boolean on success/failure. They must not cause a native trap or reboot the watch.

Observed behaviour

Native error record reports RTL Trap, RTL Error Number 0x028. The watch restarts. The app's own println log is empty because the reset happens before the buffer is flushed.

Determinism across 3 captures (key evidence)

# Date/Time uptime (ms) pageStackDepth pageStack
1 2026-10-12 16:49:56 1018683 (~17 min) 5 2498,2640,2499,2438,2501
2 2026-10-13 11:10:45 66038728 (~18.3 h) 4 2498,2640,2499,2501
3 2026-10-13 13:56:13 9919325 (~2.75 h) 2 2498,2501
  • Identical fault in all three: same backtrace, same programCounter 0x60f9d613, same rtl_reg (r0=0x20064f80, r1=0x00000002, r2=0x20276550, r3=0x201c3860, r4=0x20276304, r5=0x20064f80, r6–r9=0), same stackPointer 0x20064be0.
  • Uptime varies 60× → rules out a memory leak / OOM / time dependence.
  • pageStack common factor: every capture has 2498 at the bottom and 2501 at the top; the middle pages (2640/2499/2438) are transient. Capture #3 is the minimal repro: 2498 -> 2501 only. The fault tracks system page 2501 being pushed to the top of the stack, which coincides with the activity-save flow started by Session.save().

Request: please map system page IDs 2498 and 2501 to the actual screens — we believe 2501 is the activity save/summary page pushed by save().

Backtrace (identical in all 3 records)

0x60f25e8d 0x0058ff0d 0x0052d1f3 0x0000188d 0x005900a3 0x0001ed97 0x0052dfbf
0x00000067 0x00558319 0x005585b7 0x00563fa3 0x00000e1b 0x00546279 0x005641a7
0x00003331 0x004b6a79 0x004b676f 0x000200bd 0x004a9dd3 0x0053417b 0x00544687
0x00534351 0x6028f333 0x0058d011 0x005347f5 0x006d16f1 0x006d12b1 0x006d184f
0x006ceb69 0x0070dbcb 0x006d0507 0x0058c539

Relevant app code (follows the documented pattern)

public function stopRecordWorkout() as Void {
if ((Toybox has :ActivityRecording) && (_session != null) && (_session.isRecording() == true)) {
_session.stop();
_session.save(); // <-- crash / watch reset tracks to the save flow (page 2501)
_session = null;
}
}

We already guard with null + isRecording(), and call stop() → save() → null per the official example. Wrapping the calls in try/catch does not help, consistent with a native trap below the VM.

What we have ruled out

  • OOM / leak: free memory high; uptime varies 60× between crashes.
  • API misuse: usage matches the official docs; guarded; try/catch ineffective.

Control test in progress

We built a variant that calls Session.discard() instead of Session.save() (so the activity-save page 2501 is never pushed). We will report whether the resets stop — if so it confirms the fault is in the save() UI flow.

Attachments (available on request)

  • 3× native error records (err_log) — redacted/unredacted as needed.
  • kpi_usage.log thread/KPI dump captured on the device.
  • Minimal reproduction app source.

Impact

End users lose recorded workouts and the entire watch reboots mid-use. A public, documented CIQ API (Session.save()) should never be able to do this.