Handling Google Apps Script Execution Time Limits


If you’ve ever built a Google Apps Script that processes a lot of data or loops over long tasks, you might have seen the frustrating error.

Exceeded maximum execution time


🕒 Why does this error happen?

By design, Google Apps Script runs on Google’s servers with execution time limits to prevent scripts from hogging resources indefinitely. For simple triggers (like onOpen or onEdit), the maximum runtime is 30 seconds. For custom functions in Sheets, it’s even stricter – typically under 30 seconds.

However, for most scripts run via the Apps Script editor, time-based triggers, or menu items, the maximum execution time is 6 minutes (360 seconds) for consumer accounts. For Workspace paid accounts, it can extend up to 30 minutes under certain trigger contexts, but generally for standard executions, keep the 6-minute rule in mind.

Looping over rows in a Google Sheet

Imagine you wrote a script that loops through thousands of rows to perform some operation:

function processLargeSheet() {
  const sheet = SpreadsheetApp.getActiveSheet();
  const data = sheet.getDataRange().getValues();
  
  for (let i = 0; i < data.length; i++) {
    // Do some time-consuming operation for each row
    Utilities.sleep(500); // Simulating heavy processing
  }
  
  Logger.log("Finished processing all rows.");
}


In this example, Utilities.sleep(500) just pauses for 0.5 seconds to simulate heavy processing (e.g., calling an external API or writing to multiple services). If you have 1,000 rows, the total sleep time alone will be 1,000 x 0.5 = 500 seconds, which is over 8 minutes. The script will fail with Exceeded maximum execution time

How can you handle this?


To handle script timeouts, this code calculates the maximum allowed execution time based on whether the user has a Gmail or Workspace account and sets it as an executionThreshold. It records the script’s start time and uses a helper function, hasTimeLeft(), to check during each loop if there’s still time left to continue processing.

In the example, it processes Gmail threads one by one, and if the execution time is about to exceed the limit, it safely stops the loop. This approach ensures your script finishes within allowed limits without abrupt failures, making your automation stable even for large workloads.

// Determine if the current user is using a Gmail account
const isGmailUser = /(gmail|googlemail)/.test(Session.getActiveUser().getEmail());

// Set the execution time threshold directly (in milliseconds)
// Gmail accounts: 6 minutes, Google Workspace accounts: 30 minutes
const executionThreshold = (isGmailUser ? 6 : 30) * 60 * 1000;

// Record the script start time
const startTime = Date.now();

// Helper function to check if execution time remains
function hasTimeLeft() {
  return (Date.now() - startTime) < executionThreshold;
}

// Example function that processes inbox threads within execution limits
function saveEmailsToDrive() {
  const threads = GmailApp.getInboxThreads(0, 100);
  
  for (let i = 0; i < threads.length; i++) {
    if (!hasTimeLeft()) break;
    
    // Your logic to save email to Google Drive goes here
    Logger.log('Saving email...');
  }
}