JXA doShellScript fails from Script Menu, but works from Script Editor / Smart Rule (-10004 Error)

Hi everyone,

I’m encountering a strange context-specific issue with JXA scripts involving doShellScript in DEVONthink 4 beta 2 on macOS 15.4.1.

A JXA script using Application.currentApplication().doShellScript(…) to execute a simple curl command works perfectly fine when run directly from Script Editor. Furthermore, the same type of JXA script logic using doShellScript executes without issue when run as a Smart Rule action within DEVONthink.

However, when the exact same JXA script file used in Script Editor is placed in the DEVONthink Script Menu folder (~/Library/Application Scripts/com.devon-technologies.think/Menu/) and run from the DEVONthink Script Menu, the doShellScript call fails.

Test Script:

This JXA script demonstrates the issue.

(() => {
    'use strict';
    let resultMessageForAlert = "";

    try {
        const currentApp = Application.currentApplication();
        currentApp.includeStandardAdditions = true;

        const testCommand = "curl -s ifconfig.me";

        const result = currentApp.doShellScript(testCommand);

        resultMessageForAlert = `Success! External IP address is:\n\n${result}`;

        currentApp.displayAlert("JXA doShellScript Test Succeeded", {
            message: resultMessageForAlert,
            as: "informational"
        });

    } catch (e) {
        resultMessageForAlert = `Failure! An error occurred:\n\n${e.message || 'Unknown'} (Error Number: ${e.errorNumber || 'N/A'})`;

        try {
            Application.currentApplication().displayAlert("JXA doShellScript Test Failed", {
                message: resultMessageForAlert,
                as: "critical"
             });
        } catch (alertError) {
             console.error(`Failed to display final error alert: ${alertError}`);
             console.error(`Original error message: ${resultMessageForAlert}`);
        }
    }
})();

While this is a simplified test case, the way it calls currentApp.doShellScript(…) and the resulting error (-10004 from the menu) are exactly the same as in my original, more complex script.

Results:

Run from Script Editor: The script executes successfully and displays an alert with the external IP address.

Run from DEVONthink Script Menu… (Error Number: -10004)

Run as Smart Rule Action: The same logic works without privilege errors (tested with a more complex script).

Why would the exact same JXA script using doShellScript succeed when run from Script Editor and as a Smart Rule action, but fail with a -10004 privilege violation error only when run from the DEVONthink Script Menu?

Any help or insight would be greatly appreciated! Thanks.

DEVONthink 4 executes menu scripts using dedicated tasks (see NSUserAppleScriptTask | Apple Developer Documentation), therefore Application.currentApplication() might not support this (due to sandboxing or other restrictions) and is actually discouraged as the current application might also be a background task of DEVONthink (usually in case of smart rule, batch processing & reminder scripts) or DEVONthink on its own. A script should never assume a certain current application.

Does it work using Application("DEVONthink") instead?

1 Like

Thank you for the explanation and suggestion. I modified the script to use Application('DEVONthink') instead of Application.currentApplication().

However, it unfortunately still results in the same -10004 privilege violation error when executed from the Script Menu.

I get the same error even in the Script Editor.app over here (macOS 15.4.1) but AppleScript works in all cases:

tell application id "DNtp"
	set theResult to do shell script "curl -s ifconfig.me"
	display dialog (theResult as string)
end tell

Thanks for confirming the AppleScript version works reliably.

Yes, I’m aware that AppleScript doesn’t have this issue, as I have been using AppleScript for my automations. I’m currently in the process of converting these existing AppleScripts to JXA.

Given this conversion effort, I would prefer to find a solution within JXA, rather than reverting to AppleScript for this functionality if possible.

Does this mean there’s currently no way to reliably use JXA doShellScript from the Script Menu?

:face_with_crossed_out_eyes:

You should include the standard additions, I think

Here’s what I see for this script in Script Editor

(() => {
app = Application("DEVONthink");
curapp = Application.currentApplication();
app.includeStandardAdditions = true;
curapp.includeStandardAdditions = true;
console.log('Trying app.doShellScript');
try {
  const result = app.doShellScript("echo 'hi'");
  console.log(`Result ${result}`);
} catch (e) {
  console.log('failed');
}
console.log('Trying curapp.doShellScript');
try {
  const result = curapp.doShellScript("echo 'hi'");
  console.log(`Result ${result}`);
} catch (e) {
  console.log('failed');
}
})()

Output

/* Trying app.doShellScript */
/* failed */
/* Trying curapp.doShellScript */
/* Result hi */

That is perfectly ok (DT failing with doShellScript as well as currentApplication() succeeding).

Same script with a slight modification (replaced console.log with app.logMessage) and using function performsmartrule() instead of a self-executing anonymous function gives me this in the DT protocol window:

03.05.25, 16:01:46: Trying app.doShellScript
03.05.25, 16:01:46: failed
03.05.25, 16:01:46: Trying curapp.doShellScript
03.05.25, 16:01:46: Result hi

Again, that behavior is correct.

Finally, the last script behaves identically as external script in the smart rule.

So, I doubt that there’s a problem with running doShellScript on Application.currentApplication(). Provided that currentApplication has includeStandardAdditions set to true.

Since DT caches external scripts, you have to restart it to pick up changes you apply to external scripts.

@jch311438: Your original code did not show that doShellScript fails. It just showed that something in your try block didn’t work. My guess is that the currentApp.displayAlert() call behaves differently (or not at all) depending on what currentApp is (DT or Script Editor or whatever).
So, if you really think you’ve found a bug, narrow it down as much as possible. A try block with 6 statements is not helpful. Not for us, and not for you in testing.

By any chance, does my test script run successfully for you from the Script Menu? It consistently fails for me (-10004 error) only when run from the Menu folder (~/Library/Application Scripts/com.devon-technologies.think/Menu/), although it works fine in Script Editor and Smart Rules.

I just amended my previous post. Narrow down your code, and it will run. And ask yourself what an interactive function is doing in a script that is meant to run as part of a smart rule. Just call Application("DEVONthink").logMessage() if you need a log of your actions.

Finally, a very simple example where a script fails as external in a smart rule while it runs just fine in SE:

function performsmartrule() {
  const app = Application("DEVONthink");
  const curapp = Application.currentApplication();
  app.includeStandardAdditions = true;
  curapp.includeStandardAdditions = true;
  app.logMessage(`currentApplication is ${curapp.properties().name}`);
}

gives this in the protocol window:

03.05.25, 17:11:07: ~/Library/Application Scripts/com.devon-technologies.think/Smart Rules/DoShellScript.scpt	on performSmartRule (Error: Error: Message not understood.)

Which indicates that some things just don’t work with currentApplication in an external script for a DT smart rule. Which is ok, I think – you can do most anything on a DT application object, except for doShellScript. And that works just fine on currentApplication.

following your advice, I tested this significantly simplified script:

(() => {
	const currentApp = Application.currentApplication();
	const dt = Application('DEVONthink');
	currentApp.includeStandardAdditions = true;
	const testCommand = "curl -s ifconfig.me";
	const result = currentApp.doShellScript(testCommand);
	dt.logMessage(`${result}`);
})();

When run from Script Editor, this script works fine and logs my IP to the DEVONthink Log

However, when the exact same script file is run from the DEVONthink Script Menu, it still fails silently. Nothing is logged.

:face_with_crossed_out_eyes:

Ah, I hadn’t seen your latest comment before writing this

I suggest that you slow down a bit. The code, as you posted it here, can’t do anything anywhere: Curly quotes everywhere. I fixed that (also in your post), and this

function performsmartrule() {
const currentApp = Application.currentApplication();
const dt = Application('DEVONthink');
currentApp.includeStandardAdditions = true;
const testCommand = "curl -s ifconfig.me";
const result = currentApp.doShellScript(testCommand);
dt.logMessage(`${result}`);
}

gives me


So, it runs, and it gives the correct result. There’s nothing else I can do.

And frankly: What is the point in having an external script that doesn’t run if you can have it internally and running?

BTW: `${result}` is overengineering it a bit. Just use result, that is a string already.

Yes it seems there’s no issue within the Smart Rule context

I myself am currently using code like the following in my own working Smart Rule:

function performsmartrule(records) {
    const gistId = "...";
    const accessToken = "...";
    const app = Application("DEVONthink");
    app.includeStandardAdditions = true;
    ...

    if (...) {
        ...
        return;
    }

    records.forEach(record => {
        try {
            if (///) {
                ...
            } else {
                ...
            }
        } catch (e) {
            ...
        }
    });

    if (...) {
        ...
        const uploadCommand = `curl -X PATCH -H ...`;
        ...
        try {
             const shellApp = Application.currentApplication();
             shellApp.includeStandardAdditions = true;
             ...
             const shellResult = shellApp.doShellScript(uploadCommand);
             ...
        } catch(e) {
             ...
        }
    } else {
         ...
    }
    ...
}

The problem, however, lies with scripts run from the DEVONthink Script Menu folder (~/Library/Application Scripts/com.devon-technologies.think/Menu/).

In that specific Script Menu context, the JXA doShellScript call simply doesn’t succeed, even though the same minimal code works fine from Script Editor. Additionally, during my testing yesterday, I observed logged differences in how Application.currentApplication() behaves or presents itself in the Script Menu context compared to the Smart Rule context.

I’d simply like to find a way to make this work using pure JXA, without needing to call an external AppleScript.