DOpus.SetScheduledTimer and .KillTimer fail with "A method was called unexpectedly (0x8000ffff)"

I've had a script listening to events with scheduled timers working for quite a while, but lately, I noticed it's failing O_o

When ever I try to call DOpus.SetScheduledTimer or DOpus.KillTimer now, it throws

A method was called unexpectedly (0x8000ffff)

When I try/catch it, the error says

-2147418113: Catastrophic failure

var SAVE_TIMER = 1;

function OnInit(initData) {
	initData.name = "SaveTabGroups";
	initData.desc = "SaveTabGroups";
	initData.copyright = "(c) 2020 Benjamin Philipp";
	initData.default_enable = true;
	initData.version = "1.0.1";
	initData.log_prefix = initData.name;
	
	initData.config.maxBackups = 20;
	initData.config.maxFolders = 10; // TODO: save batches as subfolders. Maybe by day?
	initData.config.saveAsName = "AutoSave";
}

/* (...helper functions) */
/* (...setup) */

function OnScheduledTimer(data){
	if(data.id === SAVE_TIMER){
		log("Save tabs:", glob("lastTabSaveLabel"));
		saveGroup();
		return;
	}
}

// Event listener functions, for example:
function OnOpenTab(data){
	scheduleSaveGroup("openTab");
}
function OnCloseTab(data){
	scheduleSaveGroup("CloseTab");
}

// calling function
function scheduleSaveGroup(label){
	try{
		DOpus.KillTimer(SAVE_TIMER); // <-- fails lately? Without try/catch, throws "A method was called unexpectedly (0x8000ffff)"
	}
	catch(e){
		log(e); // (prints stringified error to console:) "-2147418113: Catastrophic failure"
	}
	var t = DOpus.Create.Date();
	t.Add(5, "s");
	// log("Schedule save tabs:", label, t);
	sglob("lastTabSaveLabel", label);
	lastLabel = label;
	log("Set timer?", SAVE_TIMER, t); // prints, for example. "1 '2026-08-11 15:55:31'": all seems well
	var res = DOpus.SetScheduledTimer(SAVE_TIMER, t); // <-- Same error
	return;
}

/* (...) */

Why might this be? I'm so confused :woozy_face:

It means Opus doesn't think your script has a OnScheduledTimer method.

My guess is the full script has some mismatched braces or something else which is hiding the method.

What the hell.

I found the offending piece of code in my helper functions.

function RegEsc(str){ // <-- Wanted to keep an alias around as legacy before deprecation
	log("DEPRECATION WARNING: 'RegEsc' should be 'regEsc'!");
	return regEsc(str);
}
function regEsc(str){
	return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
}

If the above stays as-is, the calls to DOpus.SetScheduledTimer etc fail.
If I change it to something like

function RegEsc(str){ // <-- Wanted to keep an alias around as legacy before deprecation
	log("DEPRECATION WARNING: 'RegEsc' should be 'reg_Esc'!");
	return reg_Esc(str);
}
function reg_Esc(str){
	return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
}

, the calls work again.

Setup as below, with the helper functions at the bottom:

var SAVE_TIMER = 1;

function OnInit(initData) {
	initData.name = "SaveTabGroups";
	initData.desc = "SaveTabGroups";
	initData.copyright = "(c) 2020 Benjamin Philipp";
	initData.default_enable = true;
	initData.version = "1.0.1";
	initData.log_prefix = initData.name;
	
	initData.config.maxBackups = 20;
	initData.config.maxFolders = 10; // TODO: save batches as subfolders. Maybe by day?
	initData.config.saveAsName = "AutoSave";
}

/* (...helper functions) */
/* (...setup) */

function OnScheduledTimer(data){
	if(data.id === SAVE_TIMER){
		log("Save tabs:", glob("lastTabSaveLabel"));
		saveGroup();
		return;
	}
}

// Event listener functions, for example:
function OnOpenTab(data){
	scheduleSaveGroup("openTab");
}
function OnCloseTab(data){
	scheduleSaveGroup("CloseTab");
}

// calling function
function scheduleSaveGroup(label){
	try{
		DOpus.KillTimer(SAVE_TIMER); // <-- fails lately? Without try/catch, throws "A method was called unexpectedly (0x8000ffff)"
	}
	catch(e){
		log(e); // (prints stringified error to console:) "-2147418113: Catastrophic failure"
	}
	var t = DOpus.Create.Date();
	t.Add(5, "s");
	// log("Schedule save tabs:", label, t);
	sglob("lastTabSaveLabel", label);
	lastLabel = label;
	log("Set timer?", SAVE_TIMER, t); // prints, for example. "1 '2026-08-11 15:55:31'": all seems well
	var res = DOpus.SetScheduledTimer(SAVE_TIMER, t); // <-- Same error
	return;
}




//////////////////////// only helper functions below ///////////////////////////////////

function glob(varname, defaultReturn, setDefaultOnEmpty) {
	defaultReturn = defaultReturn !== undefined ? defaultReturn : "";
	setDefaultOnEmpty = setDefaultOnEmpty !== undefined ? setDefaultOnEmpty : false;
	var ret = null;
	try {
		ret = DOpus.vars.Get(varname);
	} catch (e) {
		log(e);
	}
	if(typeof ret == "unknown"){ // eslint-disable-line valid-typeof
		// TODO: Does this happen? Do we need it? 
		msg("glob type unknown: " + varname);
		ret = undefined;
	}
	if (ret === undefined || (setDefaultOnEmpty && (ret === null || (ret && ret.trim && (ret.trim() === ""))))){
		// log("glob empty-ish");
		sglob(varname, defaultReturn);
		return defaultReturn;
	}
	// else{
	// 	log("no, go ahead...");
	// 	log(ret);
	// }
	return ret;
}

function sglob(varname, value) {
	DOpus.vars.set(varname, value);
}

function log(){
	var s = [];
	for(var i = 0; i<arguments.length; i++)
		s.push(arguments[i] + "");
	DOpus.Output(s.join(" "));
}

function RegEsc(str){ // <-- Wanted to keep an alias around as legacy before deprecation
	log("DEPRECATION WARNING: 'RegEsc' should be 'regEsc'!");
	return regEsc(str);
}
function regEsc(str){
	return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
}

What. The actual. F​uck. :sweat_smile:

Why does having two functions that only differ in capitalization result in timers not working? :face_with_crossed_out_eyes:

JScript has case-sensitive function names, but ActiveScripting does not.

Having two functions whose names only differ by case makes the ActiveScripting method for getting a list of a script's functions (IDispatch::GetTypeInfo) fail with error TYPE_E_AMBIGUOUSNAME.

Unfortunately the API just fails outright, rather than returning a list of the script's other functions.

Edit: We'll add a diagnostic message when this happens, so it's easier to work out what's going wrong.

Thank you! :sparkles:
That saves potentially hours of trial-and-error debugging in all the wrong places.

Might also be worth putting in the docs for JScript scripting