Trying to understand error running JXA from smart rule

I am trying to create a script that will read a date from the content of a file and then use that date to store the document in the appropriate group.

The JXAscript I created is the following:

let db_name = "_";

// Create a path based on the date.
function output_path(date) {
	// For simplicity just return a fixed path
	return  "/BTW/top/2025/Q4/example";
}

// Log both to console and to DT
function log(msg) {
	const app = Application("DEVONthink");
	app.includeStandardAdditions = true;
	app.logMessage(msg);   
	console.log(msg);
}

// Move the record to the specified path
function moveRecord(record, path) {
	const app = Application("DEVONthink");
	app.includeStandardAdditions = true;
	const db = app.databases[db_name];
	let group = app.createLocation(path, {in: db});
	let originalGroup = record.locationGroup();
	log('Moving from: ' + originalGroup.name());
	log('Moving to: ' + group.name());
	app.move({record: record, from: originalGroup, to: group});
	log('Moved');
}

function scriptoutput(record, date) {
	const app = Application("DEVONthink");
	app.includeStandardAdditions = true;
	log('Record: ' + record.name());
	log('Detected date: ' + date);
    const path = output_path(date);
	log('Path: ' + path);
	moveRecord(record, path);
	log('---');
}

(() => {
	let app = Application.currentApplication();
	let dt = Application('DEVONthink');
	app.includeStandardAdditions = true;

    const appName = app.properties()["name"];
    if (appName !== 'DEVONthink') {
		const records = dt.selectedRecords();
		console.log('Found ' + records.length + ' records');
		records.forEach(function(record) {
			// Fake the date
			scriptoutput(record, "23-07-2023");
		});
     }
})()

When I run this script from Script Editor, I get the following output in the DT log window:

15/01/2026, 23:22:36: Record: Example Document
15/01/2026, 23:22:36: Detected date: 23-07-2023
15/01/2026, 23:22:36: Path: /top/2025/Q4/example
15/01/2026, 23:22:36: Moving from: archive input
15/01/2026, 23:22:36: Moving to: example
15/01/2026, 23:22:36: Moved
15/01/2026, 23:22:36: ---

This command runs as expected and moves the document to its destination.

However, when I run this script from the Smart Rule, I get the following output in the DT log window:

15/01/2026, 23:28:21: Record: Example Document
15/01/2026, 23:28:21: Detected date: 30-11-2024
15/01/2026, 23:28:21: Path: /top/2025/Q4/example
15/01/2026, 23:28:21: Moving from: archive input
15/01/2026, 23:28:21: Moving to: example
15/01/2026, 23:28:21: Scan and archive	on scriptOutput (Error: Error: Can't convert types.)

The log shows that the script is failing on the line:

	app.move({record: record, from: originalGroup, to: group});

As far as I can tell all elements, being the record, the originalGroup and the group are identical.

What can be causing this difference in behavior?

For this to work with a SmartRule you need to invoke a function with specific syntax such as:

function performSmartRule(records) {
records.forEach(function(record) {
// Fake the date for now
scriptoutput(record, “23-07-2023”);
});
}

1 Like

I should have mentioned that I’m using the method Script with Input/Output. That method has the special method named:

function scriptoutput(record, argument) {
}

which is invoked for each selected record, and has the possibility to add an argument. As you can see the invocation works. Both the record and the date are passed into it. The record rightfully identifies where it is coming from and the date is different and is actually the date inside the document.

This is actually only intended for scripts that really return a value (and do not perform other actions). For anything else the performsmartrule handler and its Apply Script action are recommended.

Is there a way to pass an argument into that method?

However, if I need to return a value I can do that and ignore it I would guess. Still doesn’t explain the error on move does it?

Assuming that you detect the date in the smart rule, you could move that part into the script. Thus no need for an input parameter.

Can you elaborate on this. I detect the date with Scan Text. How would I get this in the script?

Since I have no access to a Mac right now, just an outline:

  • get the plaintext property of the record
  • That’s a string. Use a regular expression too extract the date from it

That’s all

Thanks. I understand. I will consider this as a fallback plan.

After reading your comment again, I wonder if I misunderstood you. If I read you correctly are you saying that the action Script with Input/Output is not supposed to make requests to DEVONThink? So the moving should be done by a subsequent action inside the rule?

If I read the documentation it states that either action is optional, which for me translates that input can be left out and output can be left out. Confusing….

As it turns out, moving a record can only be done to known groups and not to the value that is in the Script Output placeholder.

It seems like doing this using actions is a dead end. I may have to do this all in code instead as @chrillek was suggesting.

It’s only recommended if the output is desired, the input is optional. For processing multiple items the alternative approach (Apply Script) is much more efficient as the script gets called only once instead of one script for each item.