The callback isn't happening like I expect it to

I am using a script to push some notes from Drafts to Obsidian. I’ve been using variants of this system for some time, but am currently getting stuck.

Here’s the script I’m using, called from an action called Three Wins Sync Service that only contains this associated script action (which is set to async).

The script contains a query and I’ve got two files that are being captured by the query, which is confirmed by my debug text.

// See online documentation for examples
// https://docs.getdrafts.com/docs/actions/scripting


function processDraft(this_draft, file_path, wins) {
  let promise = new Promise((resolve,reject) => {
    // create and configure callback object
    var cb = CallbackURL.create();
    cb.baseURL = "obsidian://advanced-uri?vault=onering"
    cb.waitForResponse = true; 

    cb.addParameter("filepath", file_path);
    cb.addParameter("data", wins);
    cb.addParameter("mode", "prepend");
    cb.addParameter("silent", true);
    
    console.log(`CallbackURL ${cb.url}`); 

    // open and wait for result

    try { 
      console.log("Let's go..."); 
      var success = cb.open();
      console.log("Status: " + cb.status);
      console.log("success: " + success); 
      console.log('Callback: ' + JSON.stringify(cb.callbackResponse));
    } catch (e) {

      console.log("Badness: " + e)
    }

    console.log("Status000: " + cb.status);

    if (success) {
      console.log("Draft Processed " + this_draft.title); 
      resolve("Callback Done");
    } else { // something went wrong or was cancelled

      if (cb.status == "cancelled") {
        context.cancel();
        reject("No"); 
      }
      else {
        context.fail();
        reject("No"); 
      }
    }
  });

  //return setTimeout(promise, 5000); 
  return promise; 
};


async function f() {

  let file_path = "Cards/Three wins";

  // Define the tags to include and exclude
  let includeTags = ["to-obsidian"]; // Change to your tag
  let excludeTags = ["processed"]; // Change to the tag you want to exclude
  let promises = [] 

  // Query drafts that match the criteria
  let drafts = Draft.query("", "all", includeTags, excludeTags);

  if (drafts.length === 0) {
      console.log("No matching drafts found.");
  } else {
      console.log("Drafts " + drafts);
      for (const d of drafts) {
          // Perform your processing on each matching draft
          console.log(`Processing draft: ${d.uuid}`);
          console.log(`aka ${d.title}`);

          // Example: Add to Obsidian (Replace this with your actual function)
          let result = await processDraft(d, file_path, d.content).then((result) => { 
          console.log("Success in for: ", result)}).catch((e) => {console.log("Error : " + e)}); 
        
          // console.log("Promise: " + result);
      };
  }
}

f();
script.complete();

Here’s what’s happening: The first time through, this works and correctly uploads a file.

The second time through, execution seems to stop at the cb.open line. It doesn’t appear as if there’s any error thrown and nothing happens after that point.

I am using await, so my mental model is that the executions of processDraft should be running in series. Here’s the log file:

Drafts [object ActionKit.ScriptObjectDraft],[object ActionKit.ScriptObjectDraft]
Processing draft: 2F0D4830-83B7-46D0-8BA2-5A86C51F8D95
aka ## 2025-03-03
CallbackURL.addParameter: Key and value strings required
CallbackURL obsidian://advanced-uri?vault=onering&data=%23%23%202025-03-03%0A-%20%5B%20%5D%20one%20date::2025-03-03%20%23journal/win%0A-%20%5B%20%5D%20two%20date::2025-03-03%20%23journal/win%0A&filepath=Cards/Three%20wins&mode=prepend
Let's go...
Status: success
success: true
Callback: {}
Status000: success
Draft Processed ## 2025-03-03
Script step completed.
Success in for: 
Script step completed.
Processing draft: AEA709CE-4AF9-4074-A7CB-6465ACC8595E
aka ## 2025-03-04
CallbackURL.addParameter: Key and value strings required
CallbackURL obsidian://advanced-uri?vault=onering&mode=prepend&filepath=Cards/Three%20wins&data=%23%23%202025-03-04%0A-%20%5B%20%5D%20ten%20date::2025-03-03%20%23journal/win%0A-%20%5B%20%5D%2015%20date::2025-03-03%20%23journal/win%0A-%20%5B%20%5D%20twenty-four%20date::2025-03-03%20%23journal/win%0A
Let's go...

Does anyone have any insights?

Here’s the two files if that’s helpful:

Honestly, I’d start by stripping out all the async stuff. There’s rarely any need for it in Drafts and it tends to complicate troubleshooting. I didn’t actually totally digest this script, but it looks to me like you are not waiting on any completion of f, so the script is moving on to call script.complete and ending execution.

CallbackURL with waitForResponse = true already waits to complete before continuing the action…so your basic process should work fine without any need for promises/awaits, etc. Also, disable “allows async” on the script step.

Thanks for the suggestion.

With that done (including the disabling of “allow async”) , I’m now getting a timeout on the second time the function runs.

I tried to use setTimeout in the for loop to create a short delay, but it seems like I can’t find that function.

Here’s the log:

Drafts [object ActionKit.ScriptObjectDraft],[object ActionKit.ScriptObjectDraft]
Processing draft: 2F0D4830-83B7-46D0-8BA2-5A86C51F8D95
aka ## 2025-03-03
CallbackURL.addParameter: Key and value strings required
CallbackURL obsidian://advanced-uri?vault=onering&mode=prepend&data=%23%23%202025-03-03%0A-%20%5B%20%5D%20one%20date::2025-03-03%20%23journal/win%0A-%20%5B%20%5D%20two%20date::2025-03-03%20%23journal/win%0A&filepath=Cards/Three%20wins
Let's go...
Status: success
success: true
Callback: {}
Status000: success
Processing draft: AEA709CE-4AF9-4074-A7CB-6465ACC8595E
aka ## 2025-03-04
CallbackURL.addParameter: Key and value strings required
CallbackURL obsidian://advanced-uri?vault=onering&mode=prepend&filepath=Cards/Three%20wins&data=%23%23%202025-03-04%0A-%20%5B%20%5D%20ten%20date::2025-03-03%20%23journal/win%0A-%20%5B%20%5D%2015%20date::2025-03-03%20%23journal/win%0A-%20%5B%20%5D%20twenty-four%20date::2025-03-03%20%23journal/win%0A
Let's go...
Status: timeout
success: false
Callback: {}
Status000: timeout
Script step completed.

Here’s the code modified per your suggestion:

// See online documentation for examples
// https://docs.getdrafts.com/docs/actions/scripting


function processDraft(this_draft, file_path, wins) {
    // create and configure callback object
    var cb = CallbackURL.create();
    cb.baseURL = "obsidian://advanced-uri?vault=onering"
    cb.waitForResponse = true; 

    cb.addParameter("filepath", file_path);
    cb.addParameter("data", wins);
    cb.addParameter("mode", "prepend");
    cb.addParameter("silent", true);
    
    console.log(`CallbackURL ${cb.url}`); 

    // open and wait for result

    try { 
      console.log("Let's go..."); 
      var success = cb.open();
      console.log("Status: " + cb.status);
      console.log("success: " + success); 
      console.log('Callback: ' + JSON.stringify(cb.callbackResponse));
    } catch (e) {
      console.log("Badness: " + e)
    }

    console.log("Status000: " + cb.status);

  //return setTimeout(promise, 5000); 
  return success; 
};


function f() {

  let file_path = "Cards/Three wins";
  let delayInMilliseconds = 1000; //1 second




  // Define the tags to include and exclude
  let includeTags = ["to-obsidian"]; // Change to your tag
  let excludeTags = ["processed"]; // Change to the tag you want to exclude
  let promises = [] 

  // Query drafts that match the criteria
  let drafts = Draft.query("", "all", includeTags, excludeTags);

  if (drafts.length === 0) {
      console.log("No matching drafts found.");
  } else {
      console.log("Drafts " + drafts);
      for (const d of drafts) {
          // Perform your processing on each matching draft
          console.log(`Processing draft: ${d.uuid}`);
          console.log(`aka ${d.title}`);

          // Example: Add to Obsidian (Replace this with your actual function)
          let result = processDraft(d, file_path, d.content);
      };
  }
}

f();


setTimeout is not part of the JavaScript language, it’s part of APIs browsers add that are not available in Drafts.

I just did a little debugging here, and it looks like the Obsidian URI plugin chokes if it gets hit with multiple URLs quickly and never calls the callbacks…so, in fact, you are on the right track with putting a pause. My test case works great if I add a 1 second pause between each processDraft call. You can mimic setTimeout with a sleep function like this:

function sleepFor(sleepDuration){
	var now = new Date().getTime();
	while(new Date().getTime() < now + sleepDuration)
}

Then just call sleepFor(1000) between processing each draft.

Thanks, that works now (had to set the delay to 3000 to get it to work consistently)!

1 Like