What is Best Practice for Handling Script Errors in Execute Script Action?

Well, I was trying to avoid going into details, because I have something in the works, but here's what I actually do:

Through some mechanism which will be unnamed as of yet, I launch a macro that presents this prompt:

I enter the variable name, like, say "klamResult", press Enter, and this is inserted into the macro I'm working on:

Which, when expanded, looks like this:

Not currently, no.

Thanks for the confirmation.

It's nice to know that a custom handler, like Dan and I have developed, was not a waste.

May I make a feature request? If the Execute Script has an error, then the %ActionResult% should report the error message, not "OK".

Looks very similar to my sub-macro:

Great minds, and all that. :slight_smile:

Well, the saga continues. :smile:

Today I discovered a macro I had written some time ago that used a keyword in the script return variable to detect an error: "[ERROR]".

So, instead of checking for no errors (ala "OK"), this checks specifically for an error. In any case it does NOT change the return variable.

Obviously, I like both ways. But, after thinking about it, and using it some, I'm starting to like the check for "[ERROR]" better. This also allows another error return of "[USER_CANCELED]", which may need to be handled different, especially in reporting the results to the user.

So here is yet another alternated method of script error handling in a KM Execute Script Action.

####I'd love feedback from all interested as to which method you like best.


###MACRO: Script ERROR Handling TEST Ver 4.0

Script ERROR Handling TEST Ver 4.0.kmmacros (11 KB)


###The Script

### RETURNS a POSIX path like "/Users/Shared/Dropbox/" ###
property propScriptName : "Choose Folder & Return POSIX Path"

set promptStr to "Choose a FOLDER"
try
  set x to 0
  --set y to 1/x
  
  set folderPath to POSIX path of (choose folder with prompt promptStr)
on error errMsg number errNum
  
  if errNum = -128 then ## User Canceled
    set folderPath to "[USER_CANCELED]" & return & return & "SCRIPT: " & propScriptName
  else
    set folderPath to "[ERROR]" & return & return & "SCRIPT: " & propScriptName & return & "Number: " & errNum & return & errMsg
  end if
  
  
end try

return folderPath

###Example Results

If you’re going to return results, as opposed to setting KM variables, then this method is OK as long as an empty result is not valid. But if there’s ever a time when an empty result is valid, then you can’t use this method, because there’s no way to guarantee that the script actually ran.

Regardless, I don’t see a problem with returning things like “user canceled” in the result - that’s cool. But, in your example, you combine them all into one general-purpose error message, so I don’t see the point. :wink:

By the way, you should verify that whatever method you choose (in JXA scripts) works correctly in that Yosemite environment that causes the strange warnings.

And just to verify that I’m thinking correctly, we should ALWAYS (in JXA) wrap everything in a try/catch, then “return” the error message, rather than let the error bubble up via stderror, because we generally turn off “return errors” (because of the Yosemite issue), right?

All good points.

My example is just that, an example, not a finished product.

Actually, I think that if the script did not return "[ERROR]", and KM did not throw any errors, then it is a safe bet that it did actually run. Do you see some other issue?

It is easy enough to change the IF/THEN to a SWITCH/CASE, and handle each return type separately. That would probably be best in a finished product.

Well, there are two points:

  1. The error msg the user sees is different
  2. As I just said above, use SWITCH/CASE if you want to handle the different returns.

This is easily handled by:

  1. Uncheck "Include Errors" in the Execute Script action
  2. Use try/catch in the script

Yes, just like I did in my AppleScript example, and in the JXA example before that.

All said, I think we are in general agreement.

However, my main question was checking for "[ERROR]" vs "[OK]".
Do you have any thoughts on that?

Here's an updated version of my script error handler, that uses the KM Action Switch/Case to handle the various types of return from the script.

All constructive criticism and suggestions for improvement very welcome.


###MACRO: Script ERROR Handling TEST Ver 4.1

Script ERROR Handling TEST Ver 4.1.kmmacros (17 KB)

One of the cardinal rules to being a good developer is to understand that you can't know everything. I have no idea if it could return nothing, and have not run successfully. But I would never make an assumption one something like this that I don't need to. And I don't need to. If it doesn't return "OK", something failed. End of story.

One of the reasons I am adamant about things like this, is because I want to get it right and never think about it again. I want to know I've accounted for everything I can, even the unforeseen, if possible. I want the code to tell me when there's a problem. I don't want to have to guess about it.

But as I wrote to someone else today, we're not creating mission-critical software. I know you, of all people, know all about that. :slight_smile: So in the end, it's all good. Do what feels right to you. If it ends up not working, you've got other options.

OK. I can't argue with that. So, bottom line, is that all scripts should return something, with "OK" being the minimum if the script completely successfully (for macros that use the results in further Actions). Unless, of course, the point of the script it to set the Clipboard, or just display results.

So, to combine our approaches, we could do this:

Test for "OK", "[1]", "[2]", "[3]", or other text.
If we get nothing, i.e. a blank result, then treat that as an error.
(I have used "^" to denote at the start of the return string.)

Agreed?


  1. OK ↩︎

  2. ERROR ↩︎

  3. USER_CANCELED ↩︎

Well, I’m good with that, although I’d only check for OK - everything else is an error as far as I’m concerned, with the possible exception of things that actually can be canceled, which aren’t that many.

But if you go this way, it means you don’t return actual values via “return”. Personally, I’m good with that, but I didn’t think you were, so I want to remind you.

I’m sure most people would consider that overkill. Not me, obviously, but I’m used to people looking at me funny. Maybe you should think on it for a day or two, before you sit at the weird kids’ table. :slight_smile:

By the way, I had a personal chuckle today. I was talking about how we weren’t actually writing mission-critical apps, and that made me think of you. That phrase probably means more to you than to me!

The reason I like to use the KM Action option to "return results to variable" is that it makes it easy, and less error prone, for the user to set the KM variable of their choice. There are many scripts that are general purpose, like choosing file and folder, and I think it is best for the user to not have to change the script to set a different KM variable.

Due to the nature of Keyboard Maestro, I don't think I'd write any process using it that is truly mission critical. Of course, Peter might disagree with me.

No, I think Peter would agree. KM meets a particular need, and meets it extremely well, but checking a heart monitor or giving a "Go/No Go" on a launch are probably not in its scope. :slight_smile:

First, @JMichaelTX thanks for sharing your template. I also appreciate the discussion regarding the pros and cons of each approach.

The V4.1 template works perfectly on my MacBook Pro 16" (Big Sur 11.3.1 using KM 9.2).

On my Mac mini (Late 2012) (Mojave 10.14.6 also using KM 9.2), however, the template returns:

~~~ VARIABLE from Script Results ~~~
objc[1049]: Class FIFinderSyncExtensionHost is implemented in both /System/Library/PrivateFrameworks/FinderKit.framework/Versions/A/FinderKit (0x7fff9d1323f0) and /System/Library/PrivateFrameworks/FileProvider.framework/OverrideBundles/FinderSyncCollaborationFileProviderOverride.bundle/Contents/MacOS/FinderSyncCollaborationFileProviderOverride (0x110386f50). One of the two will be used. Which one is undefined.
/Users/j/Desktop/

Note, if I copy the AppleScript code to the Script Editor, I get the expected:

~~~ VARIABLE from Script Results ~~~
/Users/j/Desktop/

Anybody know what might be causing this issue?

This is caused by the process that KM uses to run AppleScripts.
To fix, uncheck "Include Errors" in the Gear menu of that Execute AppleScript Action:

image

@JMichaelTX, the change you suggested (deselect Include Errors) indeed eliminated the information that preceded the file path. Thank you!

But now I'm curious:

  1. Presumably there is no error if a folder is successfully selected. If that presumption is correct, why is the information seen on my Mojave system?

  2. Why does the state of Include Errors have no consequence on my Big Sur system?

Those would be questions for @peternlewis.

1 Like

It is a warning the system puts out because Apple chose to implement a specific class, FIFinderSyncExtensionHost, in both of two different Apple Frameworks, both of which happen to be used in this process (indirectly, they are private frameworks so not used directly).

It is essentially an Apple bug, though hopefully harmless (assuming both implementations are identical, otherwise it could have interesting quirky bugs).

Presumably Apple resolved the bug between Mojave and Big Sur which is why you don't see it in Big Sur, thus no need to turn off “Include Errors” - note that Include Errors chooses whether the output of the script is just the stdout, or also includes stderr error stream.

2 Likes

@peternlewis, thanks for the thorough explanation. It surprises me that I hadn't previously encountered this issue.