ERA Viewer: Unhandled Exception in decrement (--) operation

Hi,

I’m seeing another exception in the ERA Viewer that I’m having trouble explaining.

Error Name: Unhandled Exception
Occurrences: 2
First Occurrence: 2026-01-01
Last Occurrence: 2026-01-02
Devices:
    Venu® X1: 15.33
    Forerunner® 970: 15.33
App Versions: v1.1.2.1
Languages: deu
Backtrace:
    ViewHandler.popView:29
    PageMenuDelegate.onBack:43

The exception seems to occur at the decrement (--) operation in the following code:

private static var _stackSize as Number = 0;

public static function popView( transition as SlideType ) as Void {
    if( _stackSize < 1 ) {
        throw new GeneralException( "ViewHandler.popView called on zero view stack size" );
    }
    _stackSize--;
    WatchUi.popView( transition );
}

Do you have any idea what could trigger an exception at _stackSize-- in this context?
Is it possible that the ERA report is misleading here? I double-checked that the backtrace matches the v1.1.2.1 code.

Source file:

github.com/.../ViewHandler.mc

  • It's sometimes off by a few lines. Maybe it's the popView that's causing it?

    I had lots of trouble related to views popped, removed, not removed, removed not in the order I thought it would be, etc...

  • Not to state the obvious, but it seems that it must be either the line with "throw new GeneralException" or "WatchUi.popView" that is truly throwing the exception. I don't see how a post-decrement can throw an exception, but I could be wrong. (If _stackSize somehow become a non-Number, like Null, then I think you could get an uncatchable error, rather than an exception.)

    Seems to me that the most likely candidate is the throw line, although I guess it could also be popView.

    It's too bad that the CIQ team has not added information about the type of exception to the ERA report, as discussed a long time ago.

    The context is that Garmin removes (or omits) information about exceptions (especially the exception message) in order to prevent apps from covertly smuggling user data out. [*]

    But when this was brought up in the forums, a ciq team member agreed that it would be useful to have information about the exception *type* in the ERA report, and that they'd put that task on the wishlist (or whatever).

    But so far, it hasn't happened.

    EDIT I don't want to be accused of misrepresenting what anyone said, so here's a direct link and quote:

    https://forums.garmin.com/developer/connect-iq/f/discussion/388311/array-data-size-limit/1849875#1849875 

    (Oct 21, 2024)

    We can get the exception class name in a debug build pretty easily. In a release build that requires access to debug.xml and post-processing as is done with the ERA service.

    I'll file a ticket to add the exception class id to the log and some lookup mechanism on the backend for the ERA service.

    [*] I can imagine that a malicious (and patient) dev could still smuggle out data via the exception type - albeit extremely slowly. (e.g. use multiple exception types to represent different bits of data, and slowly exfiltrate data one exception at a time. at a minimum you would need 2 exception types, although you'd probably want at least 16.) I guess one issue with this scheme is that might it be hard (or impossible) to see the exact sequence of exceptions, in which case my scheme doesn't work at all.

    There's actually an LLM exploit that does something similar - after openAI patched an exploit which involves crafting dynamic URLs, hackers demonstrated that they could do something similar with static URLs (e.g. one URL for every letter of the alphabet and numerical digit).

  • You don't need the new feature (knowing the exception) for that: you can already do it:

    function theInformationIsintheName() {
        throw new Exception();
    }

    function realFunction() {
        ...
        if (foo) {
            theInformationIsintheName();
        }
    }

  • Seems to me that the most likely candidate is the throw line, although I guess it could also be popView.

    You’re probably right. I had assumed that if this were the GeneralException, it would show up in the ERA Viewer. If ERA does not report it, then this is the most likely explanation.

    That a GeneralException is being thrown is, in itself, an indication of a programming error that I still need to track down. In any case, my first step will be to improve the application’s error handling so it does not crash when this situation occurs.

  • You don't need the new feature (knowing the exception) for that: you can already do it:

    function theInformationIsintheName() {
        throw new Exception();
    }

    function realFunction() {
        ...
        if (foo) {
            theInformationIsintheName();
        }
    }

    Yeah good point. In that case there is really no reason to hide the exception type at all. (And nobody is claiming there is, either.)

  • You’re probably right. I had assumed that if this were the GeneralException, it would show up in the ERA Viewer. If ERA does not report it, then this is the most likely explanation.

    That a GeneralException is being thrown is, in itself, an indication of a programming error that I still need to track down. In any case, my first step will be to improve the application’s error handling so it does not crash when this situation occurs.

    It could be in popView, it's hard to say for sure.

    Unfortunately the ERA will only ever show the generic unhandled exception error message, and not any exception details, for now.

  • Yeah, I hate to say this, but I did have to split a method to multiple just to track down where an exception is really thrown. Again, the idea is the same: the function name in the stacktrace tells you.

  • For now, I have added exception handling that displays the exception to the user. I am in contact with the user community via a forum and will ask them to report back any such exceptions they encounter.

  • Yeah, that's what I kind of did. Though it's almost impossible to display any meaningful information in a datafield that can be installed in any layout, so it can be very small. I ended up displaying "E1", ... "En" depending on where the error occures. In my case it's not very useful for the user, because it means that the core functionality (reading the HR of an ANT HR sensor) doesn't work. And there's no user input either... Maybe what I could do is to display the whole exception message and scroll it right to left, like in the bottom of the TV news, but that would need so much code that I might need to remove an useful feature from the already crowded datafield code (on old devices at least)

  • In my case, this is a full-screen app. For known errors (i.e. those explicitly raised in my own code), I now display a toast notification with an associated error code. For unknown errors, a full-screen error view is shown that displays the complete error message.

    What would be really helpful is a way to retrieve the class name of the exception, but as far as I know, that is not possible.