WebTimer.CallLater Nil Object Exception

Occasionally, I will see this error in my logs.

This is being trapped at App.UnhandledException event.

The following error has occurred at APP: 0_ has occurred.

Error type: NilObjectException

Stack information: 

WebTimer.!InvokeCallLaterWithValue%%v
_CallLaterTimer.Event_Action%%o<_CallLaterTimer>
ConsoleApplication.DoEvents%%o<ConsoleApplication>i8
WebApplication.Event_Run%i8%o<WebApplication>A1s
ConsoleApplication._CallFunctionWithExceptionHandling%%o<ConsoleApplication>p
REALbasic._RuntimeRun
_Main
XojoMain

I do make a call to WebTimer.CallLater and I’m am passing the method address as a WeakRef.

WebTimer.CallLater(150,WeakAddressOf self.MyLoadMethod)

This is called in a session context, and my guess is the user has logged out (or just quit the browser) just after the WebTimer.CallLater call.

The stack makes it seem (to me at least) like the error should be being handled?

ConsoleApplication._CallFunctionWithExceptionHandling%%o<ConsoleApplication>p
REALbasic._RuntimeRun

So…

  • Is this error happening in the passed method?
  • Or is this a framework bug?
  • Should I not pass a WeakRef?

This is with Xojo 2025r3.1 running on Windows Server 2019, fully patched.

Tagging @Ricardo_Cruz :grinning_face:

Thank you,
Anthony

When you use WeakAddressOf, the object containing the method is not retained for you. So if you schedule a call with CallLater, and the referenced object goes out of scope before the trigger time, you’ll get this exception.

AddressOf will retain the object, but comes with its own side effects of course, such as keeping an object alive that you might expect to have been destroyed.

A good way to get into trouble is using AddressOf on a window method, then closing the window. It will start its closing sequence, but won’t actually destroy until the timer is fired, leaving your controls pointing to nil when it does.

HI @Thom_McGrath ,

The method being passed has its own error handling and has never thrown an unhandled exception prior to being invoked from WebTimer.CallLater

From this I’m inferring the unhandled NilObjectError is in the Console/Web framework.

This line in particular:

ConsoleApplication._CallFunctionWithExceptionHandling%%o<ConsoleApplication>p
REALbasic._RuntimeRun

implies to me this error should be being handled by Xojo?

This is why I tagged @Ricardo_Cruz , to see if he could give any insight.

No. The problem is caused by your code, not the framework, so it’s not an exception that should be caught and handled in the framework.

You have two options to resolve this.

  1. Use Timer.CancelCallLater when the handling address is being destroyed.
  2. Stop using Timer.CallLater and switch to managing a Timer yourself.

This is one of the reasons I call Timer.CallLater a ā€œslippery slope hackā€ because it seems useful, but eventually leads to problems.

No, I’m not saying the method being called is triggering the exception. The object hosting the method is nil, so the framework has to fire a nil object exception. Your method isn’t even getting called. It’s the equivalent of calling Nil.DoAThing().

Yeah I’ve come to the same conclusion. One thing I really don’t like is how CancelCallLater works. What exactly is it cancelling? If I do the following, what happens? What should happen?

Timer.CallLater(1000, AddressOf DoAThing)
Timer.CallLater(2000, AddressOf DoAThing)
Timer.CancelCallLater(AddressOf DoAThing)

I replaced it with my own CallLater module, which is very similar, but has two important distinctions:

  1. Scheduling a method call returns a unique key that is required for cancelling.
  2. Uses GetDelegateTargetMBS and GetDelegateWeakMBS to try to determine if the job is safe to invoke.

Thanks Thom & Tim,

Please note: I’m using WebTimer.CallLater, not Timer.CallLater

Tim - this method is called > 10,000 times per day and prior to it being invoked by WebTimer.CallLater, it’s never thrown an error prior. Based on this I think Thom’s on the right track?

Thom - So I’m guessing this must happen because the session has gone away?

–

Why I’m doing this:

  • The method in question loads a WebDataSource object.

  • Users would semi-regularly (lets say 50 times a day) run into issues where the WebListBox which uses the WebDataSource never loads. (it just sits there in it’s loading state showing the value of the ā€˜ProcessingMessage’ property)

  • Introducing a short delay (150ms) from the client side (which is what WebTimer.CallLater does, correct?) ā€œfixesā€ the WebListbox-is-stuck-in-processing issue

As mentioned above, this methods is called thousands of times per day and so far… I’ve only seen the unhandled exception I pasted in my original post, twice in three days.

I would like to trap the error BEFORE App.UnhandledException is raise if possible, but it sounds like that might be hard and/or impossible.

Appreciate the both of you sharing your thoughts! :grinning_face:

Anthony

Oops - And I meant to say, if there’s a better way to fix the underlying issue (WebListBox using a datasource occasionally getting "stuck in processing), I’d love to hear about it! :grinning_face:

Tim and I are saying the same thing. Unfortunately, you cannot trap this. Your options are:

  1. Don’t use Timer.CallLater (or WebTimer.CallLater in this case.)
  2. Ensure your scheduled calls are cancelled before the object is destroyed.
1 Like

Ah. I misinterpreted what Tim was saying as that the NOE was in the method being invoked.

And it sounds like you don’t have an alternative solution for my ā€œroot issueā€? (WebListbox with a WebDataSource being ā€œstuck foreverā€ in it’s processing state)

Since this issue is extremely rare, I’ll probably manage how it’s logged in App.UnhandledException and wait to see if @Ricardo_Cruz or anyone else has some insights into the ā€œroot issueā€.

Again - I really do appreciate the help.

Anthony

No, I’m no longer the expert on the web framework. I’m so disconnected from it these days, I really don’t know much about it anymore.

You said the timer introduces a delay. What is delayed?

The loading of the WebDataSource used by the WebListBox.

Would it make sense if Timer (or WebTimer) CallLater functions were improved so that they would behave more sensibly with a WeakRef?

It seems to me if the code was written to use a WeakRef, the expected behavior would be to do nothing if the WeakRef’s object had been destructed.

The framework throwing an internal nilObjectException seems ā€œsurprisingā€ to me, which violates the Principle of least astonishment - Wikipedia

1 Like

The first thing Xojo needs to do is give us a way to determine if a weak delegate is still valid. There’s currently no way to do that. MBS has a few methods, but they’re not absolutely reliable because Xojo can change things about memory usage.

Once they have that, I agree they should use it to just ignore CallLater invocations that are no longer valid.

1 Like

A bunch of issues have been raised on these, several closed but some are still open:

https://tracker.xojo.com/xojoinc/xojo/-/issues/26060
https://tracker.xojo.com/xojoinc/xojo/-/issues/40246
https://tracker.xojo.com/xojoinc/xojo/-/issues/65683
https://tracker.xojo.com/xojoinc/xojo/-/issues/65787

and probably others…

1 Like

fwiw - this:

From my perspective, I am using CallLater with WeakAddressOf because I understand the object may be destroyed between now and when the Timer fires. That’s the point of using a WeakRef. I want the Timer to catch the exception that is raised when trying to invoke the method, just as I would catch it if I were doing it.

I see the spirit of the CallLater method with WeakAddressOf as being ā€œplease invoke this after X delay if it still exists.ā€ I would never want that to raise an exception I’d have to catch in App.UnhandledException (and could only identify via the stack). And if I wanted to keep track of the state of these calls and cancel all the delayed calls before destroying the object then I wouldn’t need a WeakRef in the first place.

(from Travis Hicks on issue # 65787)

pretty well sums up my thinking/expectations when I decided to pass a WeakRef to WebTimer.CallLater

But I now understand, this isn’t how things work today. ĀÆ\(惄)/ĀÆ

Anthony

1 Like

I hadn’t had the opportunity to respond to the update about your ā€œroot issueā€ :slight_smile:

No! WebTimer only retains and restores a Session context. You have to set a WebTimer’s Location property to Browser for it to be browser-side. I’m not seeing a way to do that with WebTimer.CallLater.

Though, should you switch to a design-time WebTimer you could do this with the inspector AND take advantage of the framework handling ā€œdisconnectingā€ everything to avoid these NOEs.

Do you have a ticket regarding this WebDataSource never loading issue? I use WebDataSources to back several WebListboxes in TPLM and have never seen this issue. I wonder if it’s related to the DBMS though, you’re using MySQL or MariaDB right?

1 Like

This is the description for WebTimer in the documentation.

But looking at WebTimer.CallLater in the docs…

Makes it seem like what you’re saying is correct @Tim_Parnell

Feels like the documentation could be a little clearer here?

It does but CallLater is shared. You’re not calling it on any specific instance, so there is no location set. WebTimer.CallLater doesn’t actually use a WebTimer at all. I’m pretty confident it’s an alias for Timer.CallLater.

Edit… why does WebTimer.CallLater even exist? It’s not like Timer.CallLater isn’t available to web projects.