Bug Report: AppleScript Fails When Run from File (KM 7.3.1)

##bug Report: AppleScript Fails When Run from File
Running Keyboard Maestro 7.3.1 (7.3.1) on macOS 10.11.6

There appears to be a bug somewhere (not sure where) that causes the AppleScript in the below Macro to fail when it is run from a file.

  • Runs fine as text
  • Runs fine from Script Editor 2.8.1 (183.1)
  • Runs fine from Script Debugger 6.0.4 (6A198)
  • I have created a new macro from scratch in another Group, but it still fails.

Error Msg:

/Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI Clean Save in SE.scpt: execution error: Can’t get text 1 thru 4888 of " ". (-1728)


Sorry, but it is a long script:
The original (which also fails) was written by @ccstone.  I made some minor mods to output path of selected UI element. 

###Purpose
* Scan the Frontmost Window UI to produce a report of all UI Elements.
* Provide the UI Path to a Chosen Element

**Notice:  This script requires  [Satimage.osax](http://www.satimage.fr/software/en/downloads/downloads_companion_osaxen.html).**

```applescript
--~~~~~~~ CLEAN SAVE IN SCRIPT EDITOR ~~~~~~~~~~
--------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2016/06/11 05:40
# dMod: 2016/06/13 15:01
# Appl: System Events
# Task: Report System Events UI Information for the Front Window of the Front app.
# Libs: None
# Osax: None
# Aojc: True
# Tags: @Applescript, @Script, @System_Events, @Analyze, @Front, @Window
# Vers: 1.50
#
# REQUIRES:   Satimage.osax
#             http://www.satimage.fr/software/en/downloads/downloads_companion_osaxen.html
--------------------------------------------------------------------------------
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions

property LF : linefeed

--------------------------------------------------------------------------------
# If you haven't changed your default text editor these two options will be eqivalent.
property outputType : "Default Text Editor" --> Alternative: "TextEdit"
--------------------------------------------------------------------------------

set tabPad to "                                        "

tell application "System Events"
  set frontProcess to first process whose frontmost is true
  
  tell frontProcess
    set processName to its name
    tell front window
      set windowName to its name
      set entireContentsOfWindow to entire contents
      set winSubRole to subrole
    end tell
    try
      goofy of entireContentsOfWindow
    on error forcedErrorText
    end try
  end tell
end tell

set AppleScript's text item delimiters to {"{", "}"}
set forcedErrorText to text item 2 of forcedErrorText

set forcedErrorText to its cngStr:" of application process \"[^\"]*\" of application \"[^\"]*\"(?:, )?" intoString:linefeed inString:forcedErrorText
set forcedErrorText to paragraphs of forcedErrorText

copy forcedErrorText to elemList

##return forcedErrorText

repeat with theLine in forcedErrorText
  
  
  set tabCnt to ofCount(theLine)
  set tempText to (its cngStr:" \\bof\\b.+" intoString:"" inString:theLine)
  if tabCnt > 0 then
    set tempText to text 1 thru tabCnt of tabPad & tempText
  end if
  set contents of theLine to tempText
  
end repeat

set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
set forcedErrorText to forcedErrorText as text
set AppleScript's text item delimiters to oldTIDS
set forcedErrorText to "application Process \"" & processName & "\"" & linefeed & ¬
  tab & "window " & windowName & linefeed & ¬
  forcedErrorText

--------------------------------------------------------------------------------
--» OUTPUT
--------------------------------------------------------------------------------
--set the clipboard to forcedErrorText
set AppleScript's text item delimiters to linefeed
set reportStr to change tab into "   " in forcedErrorText

set reportList to text items of reportStr
set AppleScript's text item delimiters to oldTIDS

set frontApp to path to frontmost application as text
tell application frontApp
  set elemSel to choose from list reportList
end tell

if (elemSel ≠ false) then
  set elemPos to (my getItemPos(elemSel, reportList)) - 2
  
  set AppleScript's text item delimiters to ""
  ## (elemPos & ": " & elemSel as text)
  set elemPath to (item elemPos of elemList) as text
  set winWhose to "(first window whose subrole is \"" & winSubRole & "\")"
  set elemPath to change "window .+$" into winWhose in elemPath with regexp
  
  set scriptResults to "PATH TO SELECTED ELEMENT:" & LF & elemPath & LF & LF & reportStr
  
else -- Choose List was Canceled --
  
  set scriptResults to reportStr
  
end if

return scriptResults


--------------------------------------------------------------------------------
--» HANDLERS
--------------------------------------------------------------------------------

on getItemPos(pItemToFind, pListToSearch)
  if (class of pItemToFind = list) then set pItemToFind to item 1 of pItemToFind as text
  
  repeat with i from 1 to count of pListToSearch
    if item i of pListToSearch is pItemToFind then return i
  end repeat
  return 0
  
end getItemPos

on cngStr:findString intoString:replaceString inString:dataString
  set anNSString to current application's NSString's stringWithString:dataString
  set dataString to (anNSString's ¬
    stringByReplacingOccurrencesOfString:findString withString:replaceString ¬
      options:(current application's NSRegularExpressionSearch) range:{0, length of dataString}) as text
end cngStr:intoString:inString:
--------------------------------------------------------------------------------
on createDirectoryAtPath:thePath
  set {theResult, theError} to current application's NSFileManager's defaultManager()'s createDirectoryAtPath:thePath withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
  if not (theResult as boolean) then
    set errorMsg to theError's localizedDescription() as text
    error errorMsg
  end if
end createDirectoryAtPath:
--------------------------------------------------------------------------------
# Open in default editor for text files set in the Finder Get-Info window.
--------------------------------------------------------------------------------
on outputToDefaultTextEditor(_text)
  set dirPath to POSIX path of (path to temporary items from user domain as text)
  set filePath to dirPath & "Window_UI_Exploration.txt"
  its createDirectoryAtPath:dirPath
  its writeString:_text toPath:filePath
  set shCMD to "
  open -t " & qf(filePath) of me
  do shell script shCMD
end outputToDefaultTextEditor
--------------------------------------------------------------------------------
on ofCount(_text)
  set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " of "}
  set theCount to length of (text items of _text)
  set AppleScript's text item delimiters to oldTIDS
  return theCount
end ofCount
--------------------------------------------------------------------------------
on outputToTextEdit(_text)
  do shell script "echo " & qf(_text) of me & " | open -f"
end outputToTextEdit
--------------------------------------------------------------------------------
on qf(_text)
  return (quoted form of _text)
end qf
--------------------------------------------------------------------------------
on writeString:aString toPath:posixPath
  set anNSString to current application's NSString's stringWithString:aString
  anNSString's writeToFile:posixPath atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeString:toPath:
# Other encodings: NSMacOSRomanStringEncoding
--------------------------------------------------------------------------------

```

###MACRO:   @TEST @AppleScript UI Elem

~~~ VER: 1.0    2017-06-15 ~~~

####DOWNLOAD:
<a class="attachment" href="/uploads/default/original/2X/0/01b53c886b16ebfb162f8095726ffb8592563a83.kmmacros">@TEST @AppleScript UI Elem.kmmacros</a> (15 KB)
**Note: This Macro was uploaded in a DISABLED state. You must enable before it can be triggered.**

---

###Use Case

* 

---

###ReleaseNotes

/Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI Clean Save in SE.scpt: execution error: Can’t get text 1 thru 4888 of "																				". (-1728)

---

<img src="/uploads/default/original/2X/b/b34143ed5ac2fcccf5a0201473b033aacba50f9c.png" width="448" height="979">

What result do you get if you run it from osascript?

According to osstatus.com, error -1728 is errAENoSuchObject.

Sounds like it is failing to get an object and the text from that object.

Haven't tried it.

Can you duplicate the bug?

I didn’t try it - I don’t usually run scripts and you didn’t even say what it does, so without looking at it closely I wouldn’t even know if I had whatever apps it needs, or when to run it or what setup it needs.

In any event, Keyboard Maestro runs AppleScript files the same way it runs AppleScript text:

osascript /path/to/file

So if it is a script file, that should get the same result unless it is somehow dependent on the inherited environment of Keyboard Maestro Engine.

Seems to fail in Script Editor here. Perhaps a clue

Thanks for testing.

The error you show is a syntax error, quite different from the execution error I'm reporting when run from KM.

I believe the error you are seeing may be because you do not have the Satimage.osax installed. My fault for not making this requirement clear at the top of the script.

I get a completely different error when run from Terminal:

osascript /Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI\ Clean\ Save\ in\ SE.scpt

/Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI Clean Save in SE.scpt: execution error: System Events got an error: osascript is not allowed assistive access. (-1719)


But after giving Terminal Accessibility permission, I now get the same error as when run from KM:

> /Users/Shared/Dropbox/SW/DEV/KM/Scripts/UI Clean Save in SE.scpt: execution error: Can’t get text 1 thru 38 of "						". (-1728)

And I get same error (but different text range) when run from FastScripts:

Error Number: -1728

Can’t get text 1 thru 357 of " ".

FWIW, I get the same error when I run Chris' (@ccstone) original script from file:

/Users/Shared/Dropbox/SW/DEV/KM/Scripts/Window Analysis Tool for System Events v1.50 @ccstone @AS.scpt: execution error: Can’t get text 1 thru 357 of " ". (-1728)

###Original Script by @ccstone
I could be wrong, but I think that this script does NOT require/use Satimage.osax.
It builds a list of UI elements of the frontmost window, and then opens the list in either BBEdit or TextEdit.

--------------------------------------------------------------------------------
# Auth: Christopher Stone
# dCre: 2016/06/11 05:40
# dMod: 2016/06/13 15:01
# Appl: System Events
# Task: Report System Events UI Information for the Front Window of the Front app.
# Libs: None
# Osax: None
# Aojc: True
# Tags: @Applescript, @Script, @System_Events, @Analyze, @Front, @Window
# Vers: 1.50
--------------------------------------------------------------------------------
use AppleScript version "2.4"
use framework "Foundation"
use scripting additions
--------------------------------------------------------------------------------
# If you haven't changed your default text editor these two options will be eqivalent.
property outputType : "Default Text Editor" --> Alternative: "TextEdit"
--------------------------------------------------------------------------------

set tabPad to "                                        "

tell application "System Events"
  set frontProcess to first process whose frontmost is true
  tell frontProcess
    set processName to its name
    tell front window
      set windowName to its name
      set entireContentsOfWindow to entire contents
    end tell
    try
      goofy of entireContentsOfWindow
    on error forcedErrorText
    end try
  end tell
end tell

set AppleScript's text item delimiters to {"{", "}"}
set forcedErrorText to text item 2 of forcedErrorText
set forcedErrorText to its cngStr:" of application process \"[^\"]*\" of application \"[^\"]*\"(?:, )?" intoString:linefeed inString:forcedErrorText
set forcedErrorText to paragraphs of forcedErrorText
repeat with theLine in forcedErrorText
  set tabCnt to ofCount(theLine)
  set tempText to (its cngStr:" \\bof\\b.+" intoString:"" inString:theLine)
  if tabCnt > 0 then
    set tempText to text 1 thru tabCnt of tabPad & tempText
  end if
  set contents of theLine to tempText
end repeat

set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, linefeed}
set forcedErrorText to forcedErrorText as text
set AppleScript's text item delimiters to oldTIDS
set forcedErrorText to "application Process \"" & processName & "\"" & linefeed & ¬
  tab & "window " & windowName & linefeed & ¬
  forcedErrorText

--------------------------------------------------------------------------------
--» OUTPUT
--------------------------------------------------------------------------------

if outputType = "TextEdit" then
  outputToTextEdit(forcedErrorText)
else if outputType = "Default Text Editor" then
  outputToDefaultTextEditor(forcedErrorText)
end if

--------------------------------------------------------------------------------
--» HANDLERS
--------------------------------------------------------------------------------
on cngStr:findString intoString:replaceString inString:dataString
  set anNSString to current application's NSString's stringWithString:dataString
  set dataString to (anNSString's ¬
    stringByReplacingOccurrencesOfString:findString withString:replaceString ¬
      options:(current application's NSRegularExpressionSearch) range:{0, length of dataString}) as text
end cngStr:intoString:inString:
--------------------------------------------------------------------------------
on createDirectoryAtPath:thePath
  set {theResult, theError} to current application's NSFileManager's defaultManager()'s createDirectoryAtPath:thePath withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
  if not (theResult as boolean) then
    set errorMsg to theError's localizedDescription() as text
    error errorMsg
  end if
end createDirectoryAtPath:
--------------------------------------------------------------------------------
# Open in default editor for text files set in the Finder Get-Info window.
--------------------------------------------------------------------------------
on outputToDefaultTextEditor(_text)
  set dirPath to POSIX path of (path to temporary items from user domain as text)
  set filePath to dirPath & "Window_UI_Exploration.txt"
  its createDirectoryAtPath:dirPath
  its writeString:_text toPath:filePath
  set shCMD to "
  open -t " & qf(filePath) of me
  do shell script shCMD
end outputToDefaultTextEditor
--------------------------------------------------------------------------------
on ofCount(_text)
  set {oldTIDS, AppleScript's text item delimiters} to {AppleScript's text item delimiters, " of "}
  set theCount to length of (text items of _text)
  set AppleScript's text item delimiters to oldTIDS
  return theCount
end ofCount
--------------------------------------------------------------------------------
on outputToTextEdit(_text)
  do shell script "echo " & qf(_text) of me & " | open -f"
end outputToTextEdit
--------------------------------------------------------------------------------
on qf(_text)
  return (quoted form of _text)
end qf
--------------------------------------------------------------------------------
on writeString:aString toPath:posixPath
  set anNSString to current application's NSString's stringWithString:aString
  anNSString's writeToFile:posixPath atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
end writeString:toPath:
# Other encodings: NSMacOSRomanStringEncoding
--------------------------------------------------------------------------------

Looks like this is a very consistent, repeatable error.
I just confirmed it on another Mac (MBP-15R), also running Keyboard Maestro 7.3.1 (7.3.1) on macOS 10.11.6.

Ahh, good, I was going to suggest temporarily giving Terminal Accessibility permissions. At least that narrows things down (and gets Keyboard Maestro off the hook).

A nuisance that you don’t get the error in Script Debugger.

Can you track down exactly what line is giving you the problem? Add something that fails to the script and keep moving it later until you find the offending command.

Yeah, tomorrow I'll use the tried-and-true divide-and-conquer technique.
I'll add a dialog, or return at mid-point in the script, and then move forward/backwards by 50% until I've nailed it down.

It runs fine here when launched from within KM, SD and SE, but not when launched “from file” via FS or Apple’s Script menulet (-> error -1728). Oddly, it runs fine when launched from file via LaunchBar.

When it runs fine I get for example group 1 as content of the variable tempText (about line 61); when it doesn’t run (-1728) I get «class sgrp» 1 for the tempText variable. So I guess this is some NSString issue (the cngStr function, ~line 126). Just a guess.

Thanks for testing the script, Tom.
I'll take a look at isolating that function.