Skip to main content
Inspiring
November 29, 2017
Question

Messy error messages across pcall()

  • November 29, 2017
  • 1 reply
  • 1781 views

I'm trying to clean up error handling in a plugin I'm writing and I see behavior I don't understand:

I'm in function A started with postAsyncTaskWithContext() and at the top of function A I call LrDialogs.attachErrorDialogToFunctionContext( context ).

- If I then throw an error from function A using LrErrors.throwUserError( 'test' ), I get a nice clean dialog box with the contents "test". Great - as expected.

- If I pcall() another function B from function A and call LrErrors.throwUserError( 'test' ) from B, the contents of the dialog box are "[string 'myfile.lua']:123: <AgErrorText>test</AgErrorText>". Not great. Any ideas why pcall is causing this?

Also: both dialog boxes happen twice - dismiss it and it comes right back with the same contents a second time. Dismiss that and it goes away.

If it helps, I am using johnrellis​'s debugging toolkit and my plugin is currently named with .lrdevplugin. Function A is actually invoked with :

     LrFunctionContext.postAsyncTaskWithContext( 'myMain', Debug.showErrors ( myMain ) )

I also observe that when I pcall B from A, if I wrap that with LrTasks.pcall( Debug.showErrors( B ) ) then I get 3 error dialogs instead of 2 and the first one is clean and the last two are messy.

Hopefully this is some combo of me not understanding proper flow in LR error handling and/or John's Debug toolkit?

Thanks,

db

This topic has been closed for replies.

1 reply

johnrellis
Legend
November 29, 2017

Hmm, I'm not able to reproduce that behavior with a test script.  But if you could produce a stripped down sample script showing the behavior, I'll dig into it and produce accurate diagnoses and recommendations. Some initial thoughts and questions:

- Are you using the latest version of my Debugging Toolkit, 1.7, or do you have an earlier version?

- None of task handling and error handling in LR is well-documented (and that goes for the toolkit as well). The toolkit does tries to work with this undocumented behavior as well as it can, which may be imperfect in your case, but I'm not sure.

- LrErrors.throwUserError (e) wraps "e" with <AgErrorText>e</AgErrorText>.  Here's the actual Lua error strings thrown by error() and throwUserError():

error ("xxx") => "[string \"dfburns.lua\"]:16: xxx"

throwUserError ("xxx") => "[string \"dfburns.lua\"]:17: <AgErrorText>xxx</AgErrorText>"

When the code invoked by LrDialogs.attachErrorDialogToFunctionContext() catches the error using pcall(), it parses it.  If it finds <AgErrorText>e</AgeErrortText>, it shows just "e" in the dialog, otherwise it shows "internal error" followed by the entire error string.

- You said your plugin currently ends with ".lrdevplugin". When the toolkit is initialized with Debug.init(), then if the plugin directory ends with ".lrdevplugin", showErrors() will invoke the debugger when errors are caught, and when the plugin directory ends with ".lrplugin" (i.e. in production), showErrors() will handle errors with LrDialogs.attachErrorDialogToFunctionContext().   Since you're not seeing the debugger invoked, it sounds like you've explicitly disabled debugging with Debug.init (false)?

- Since showErrors() itself invokes attachErrorDialogToFunctionContext(), you shouldn't use both in the same task.

- Don't use LrTasks.pcall (showErrors (f)).  Do either LrTasks.pcall (f) or Debug.pcall (f).  (This is buried in the documentation for the toolkit.) First, if you're invoking pcall(), by definition you want to catch and handle the error right there explicitly without invoking a default error handler.  Second, Debug.pcall() allows the toolkit debugger to do stack tracing, breakpoints, and stepping through the pcall(), whereas LrTasks.pcall() does not.  (Believe it or not, internally LrTasks.pcall() creates an additional Lua task in which to call the function, probably something to do with LR's task scheduler.)

DFBurnsAuthor
Inspiring
November 29, 2017

Sounds like I need to make a few adjustments to my code. Once I do those and can still reproduce the behavior, I'll try to post a test script. To answer your points:

- I was not up to 1.7 of Debug.lua but am now.

- My plugin currently ends in .lrdevplugin. Right now, I want to test how my error handling will look to an end-user without having to rename to .lrplugin. Am I correct that passing false to Debug.init() is the right way to do this test? (Now that I'm on 1.7, I'm having trouble avoiding the debugger window when I just want Lr's error dialog to show. Looking around for why that is...)

- When you say "Since showErrors() itself invokes attachErrorDialogToFunctionContext(), you shouldn't use both in the same task." For my clarity, you mean I shouldn't wrap a task function with Debug.showErrors and then inside that function call attachError... Correct?

- For your last point, what about the scenario where I want to catch an error but then immediately throw a new one with a better error message that is ok for a default handler to catch? What's best practice for this when trying to take advantage of the debug toolkit?

db

johnrellis
Legend
November 29, 2017

- My plugin currently ends in .lrdevplugin. Right now, I want to test how my error handling will look to an end-user without having to rename to .lrplugin. Am I correct that passing false to Debug.init() is the right way to do this test?

That's correct.