Crash on real device (Array Out Of Bounds) when updating CustomMenu - sideloading & settings?

Hi all,

I'm currently facing a crash that only occurs on my physical device (Epix 2 Pro). The same test case runs fine in the simulator.

The issue happens when the app manipulates a CustomMenu - specifically when removing items or replacing them using CustomMenu.updateItem(). On the device, this causes a crash.

I was able to retrieve the CIQ_LOG, which reports an "Array Out Of Bounds Error", but it doesn't include a stack trace. Here's the relevant part of the log:

Error: Array Out Of Bounds Error
Time: 2025-05-19T19:36:09Z
Part-Number: 006-B4313-00
Firmware-Version: 20.22
Language-Code: eng
ConnectIQ-Version: 5.1.1
Store-Id: 8a6b62f1-5450-4912-8799-2eeaf9779d97
Store-Version: 44
Filename: F56A2548
Appname: openHAB
Stack:

Now to my main questions:

  1. To get a proper stack trace, I assume I need to sideload a debug build - is that correct?

  2. If I sideload the debug build, is there any way to preserve the user settings from the store-installed version? Or do I have to hardcode them in the debug build?

  3. Has anyone run into similar CustomMenu update crashes on-device but not in the simulator?

Thanks in advance for any help or suggestions!

  • It's always tricky to change collections while they are being used.

    I mean, this sounds like a bug on Garmin's side. deleteItem() shouldn't be implemented and exposed to the dev if it won't work in all situations.

  • Good news: the switchToView workaround seems to solve the issue. It triggers a proper refresh of the CustomMenu, and the best part is that it preserves the current focus - so the transition is smooth and completely unnoticeable to the user.

    The basic pattern looks like this:

    WatchUi.switchToView(
        WatchUi.getCurrentView()[0] as View,
        WatchUi.getCurrentView()[1] as InputDelegate,
        WatchUi.SLIDE_IMMEDIATE
    );
    WatchUi.requestUpdate();
  • I mean, this sounds like a bug on Garmin's side. deleteItem() shouldn't be implemented and exposed to the dev if it won't work in all situations.

    Yes, I agree. It seems the developer who implemented this in the simulator actually got it right. It would be interesting to know whether this issue affects all devices or just specific ones. From what I understand, Menu2/CustomMenu is a native, device-specific implementation?

  • I understsand what you're trying to do, but I think it's an edge case. In java I see many similar crashes when someone modifies (doesn't matter in which way) a non synchronized object while also using it. The typical thing is to loop over some collection while also adding.removing from it. I'd be surprised if Garmin could or even wanted to "fix" (maybe better word is to address) this. I think your only chance is to find a workaround that does what you want to see and isn't too flicky for the user.

  • I don't think synchronization is the issue here. Since CIQ apps are single-threaded, most operations are effectively synchronized by default. The real problem is that Garmin performs some initialization the first time a view is shown and then assumes the number of menu items remains constant—even though it exposes functions for adding and removing items.

    While the addItem function is necessary to support programmatically building static menus, the presence of deleteItem clearly suggests some intent for menus to be dynamic. That said, I agree it's an edge case—most apps probably don't need to update their menus dynamically like this.

  • Yes, I understand that it's 1 thread. But as it looks the implementation "caches" some values, and looks like is only really tested for changing the text, value, but not the size of the list. And yes, I get it, that having a deleteItem method calls for it to be used :) So you convinced me that this is a bug worth to report.