Zapier Folder Creation Script Failing w/ "Too Many Requests"

I’m using the folder creation script here and I’m getting an error from Zapier:

Failed to create a run javascript in Code by Zapier

Error: [Network error creating folder SoundDesign: 429, Too Many Requests

This script worked for a long while, then suddenly stopped working. It does create some of the folders, but stops at random places. My code below:

/**
/ This sample code demonstrates applying a Folder template to a Frame.io Project.
/ A Zapier Code Step must be configured to catch webhook events emitted by Frame.io.
/ Learn about Frame.io webhooks: https://docs.frame.io/docs/webhooks
/ Learn about using JavaScript in Zapier: https://zapier.com/help/create/code-webhooks/use-javascript-code-in-zaps
*/

// Destructure Zapier-defined variables
const { teamId, userId, resourceId, AUTH_TOKEN_KEY } = inputData;

// Frame.io variables.  To run on Zapier you must provide your API Token
const AuthHeader = {
    Authorization: `Bearer ${AUTH_TOKEN_KEY}`,
    'Content-Type': 'application/json'
    };
const API_URL = "https://api.frame.io/v2";

// This template defines a folder tree three levels deep
const template = [
    {
      "name": "Intake",
      "type": "folder",
    },
    {
      "name": "9_ProjectFiles",
      "type": "folder",
    },
    {
      "name": "8_Creative",
      "type": "folder",
      "folders": [
          {
              "name": "Stylframes",
              "type": "folder"
          },
          {
              "name": "Storyboards",
              "type": "folder"
          },
          {
              "name": "Script",
              "type": "folder"
          },
      ]
    },
    {
      "name": "7_Production",
      "type": "folder",
      "folders": [
          {
              "name": "Locations",
              "type": "folder"
          },
          {
              "name": "Casting",
              "type": "folder"
          },
      ]
    },
    {
      "name": "5_Sound",
      "type": "folder",
      "folders": [
          {
              "name": "VO",
              "type": "folder"
          },
          {
              "name": "SoundDesign",
              "type": "folder"
          },
          {
              "name": "OMF",
              "type": "folder"
          },
          {
              "name": "Music",
              "type": "folder"
          },
          {
              "name": "Mix_Splits",
              "type": "folder"
          },
      ]
    },
    {
      "name": "4_Media",
      "type": "folder",
    },
     {
      "name": "3_Assets",
      "type": "folder",
      "folders": [
          {
              "name": "Vector",
              "type": "folder"
          },
          {
              "name": "Stills",
              "type": "folder"
          },
          {
              "name": "Ref",
              "type": "folder"
          },
          {
              "name": "Faster",
              "type": "folder"
          },
          {
              "name": "LUT",
              "type": "folder"
          },
          {
              "name": "Fonts",
              "type": "folder"
          },
          {
              "name": "Sequence",
              "type": "folder"
          },
      ]
    },
     {
      "name": "2_Shots",
      "type": "folder",
    },
    {
        "name": "1_Edits",
        "type": "folder"
    }
];

/* Every Project in Frame.io has a root_asset_id acting as a 'parent' 
/ node to 'children' beneath it.  This function returns the
/ root_asset_id for a Project. */

async function getRootAssetId(resourceId) {
    let url = `${API_URL}/projects/${resourceId}`;
    let options = {
        method: 'GET',
        headers: AuthHeader,
    };
    let response = await fetch(url, options).catch(err => {
        console.error(`Error fetching root id for ${resourceId}: ${err}`);
        throw err;
    });
    if (!response.ok) {
      throw new Error(`Network error fetching root id for ${resourceId}: ${response.status}, ${response.statusText}`);
    } else {
        let jsonResponse = await response.json();
        return jsonResponse.root_asset_id;
    }
}

async function createFolder(name, parentId) {
    let url = `${API_URL}/assets/${parentId}/children`;
    let body = {
        type: "folder",
        name: name,
    };
    let options = {
        method: 'POST',
        headers: AuthHeader,
        body: JSON.stringify(body)
    };
    console.log(`Attempting to create folder: ${name}`);
    let response = await fetch(url, options).catch(err => {
        console.error(`Error creating folder: ${name}: ${err}`);
        throw err;
    });

    if (!response.ok) {
        throw new Error(`[Network error creating folder ${name}: ${response.status}, ${response.statusText}`);
    } else {
        let result = await response.json();
        return result.id;
    }
}

/* Recursive function creates each folder in the template using preorder traversal */

const runTemplater = async (template, parentId) => {
    while (template.length) {
        let item = template.shift();
        if (item.type === 'folder') {
            let newParentId = await createFolder(item.name, parentId).catch(err => {
                console.error(`folder creation error: ${item.name}: ${err}`);
                throw err;
            });           
            console.log(`runTemplater successfully created folder: ${item.name}`);
            if (item.folders) {
                await runTemplater(item.folders, newParentId);
            }
        }
    }
    return;
};

let root = await getRootAssetId(resourceId);
await runTemplater(template, root);
return {};
type or paste code here

Hi there, the issue you’re running into is described in the error description - the script is simply making too many requests within the given timeframe.

In the past the rate-limits may have been higher or potentially you’re creating additional assets somewhere else in your account. Our rate-limits are shared across your entire user login, whether you’re in transfer app, web app, one of our other apps, or using an API integration like Zapier.

This particular rate limit is 5 per second which should all you to create 300 folders per minute. The most likely source of your problem is that our API response times have gotten quicker so the script now runs faster than it used to and thus runs into the limit.

You might just need to add a slight wait in between the function calls in order to avoid adding exponential back-off and retry handling.

Thanks, how do I add in the wait times? I didn’t write this script (pretty sure you did on the old chat?). Dangerous enough to insert/add to it, but not sure what to be adding.

I’m on a flight back from IBC right now with pretty bad WiFi but I’ll look into this tomorrow! I haven’t tried to add a setTimeout() in JavaScript in Zapier before, but I imagine it’d work.

Looks like the maximum time a code step can run for is 30 seconds. That should allow for creation of a maximum of 150 folders to be created within that timeframe technically.

I’m assuming that’s far more than you need?

Yes, that’s far more than we have/need.

@jhodges any luck on this? Kinda fell off my radar, but still looking for a fix if you have any suggestions.