GASで「Exceeded maximum execution time」エラーが発生する原因と解決策

最終更新日: 2026-08-27

💡 このエラーを含む【Google Apps Script (GAS)エラー完全攻略ハンドブック】をnoteで公開中 →

30秒でわかる原因と解決策

原因: Google Apps Script(GAS)には1回あたりの最大実行時間制限(通常アカウントは6分、有料Workspaceアカウントは30分)が設定されており、大量のデータをループ処理などで一気に処理しようとすると、この制限時間を超えてしまいエラーが発生します。 解決策: 処理を小さな単位に分割(バッチ処理)し、PropertiesServiceなどを使って「どこまで処理したか」を保存・記憶させます。その後、時間主導型トリガーをプログラムから動的に設定して、処理を自動で継続させましょう。

修正コード(Before / After)

❌ エラーが発生するコード

// 大量の行を一気に処理しようとして6分の制限に引っかかる例
function processAllRows() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var rows = sheet.getDataRange().getValues();
  
  // データの行数が数千行以上ある場合、ここでタイムアウトしやすい
  for (var i = 1; i < rows.length; i++) {
    // 重い処理(外部API呼び出しや複雑な計算など)
    Logger.log("Processing row: " + i);
    // 例: 重い外部API連携
    UrlFetchApp.fetch("https://api.example.com/data?id=" + rows[i][0]);
  }
}

⭕ 修正後の推奨コード

// 制限時間内に終わるよう処理を分割し、トリガーで継続する例
function processInBatches() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  var rows = sheet.getDataRange().getValues();
  var props = PropertiesService.getScriptProperties();
  
  // 前回の続きのインデックスを取得(初期値は1行目のデータ)
  var startIndex = parseInt(props.getProperty('LAST_INDEX') || '1', 10);
  var batchSize = 50; // 1回あたりの処理件数
  var startTime = new Date().getTime();
  var timeLimit = 4 * 60 * 1000; // 安全のため4分で打ち切る
  
  for (var i = startIndex; i < rows.length; i++) {
    // 制限時間が近づいたら中断
    if (new Date().getTime() - startTime > timeLimit) {
      props.setProperty('LAST_INDEX', i.toString());
      setupContinuationTrigger();
      Logger.log("タイムアウト防止のため中断します。次回インデックス: " + i);
      return;
    }
    
    // 重い処理の実行
    UrlFetchApp.fetch("https://api.example.com/data?id=" + rows[i][0]);
  }
  
  // すべて完了したらプロパティをクリア
  props.deleteProperty('LAST_INDEX');
  Logger.log("すべての処理が完了しました。");
}

// 継続用のトリガーを設定するヘルパー関数
function setupContinuationTrigger() {
  // 既存の同名トリガーが重複しないように削除
  var triggers = ScriptApp.getProjectTriggers();
  triggers.forEach(function(trigger) {
    if (trigger.getHandlerFunction() === 'processInBatches') {
      ScriptApp.deleteTrigger(trigger);
    }
  });
  
  // 1分後に再実行するトリガーを作成
  ScriptApp.newTrigger('processInBatches')
    .timeBased()
    .after(1 * 60 * 1000)
    .create();
}

よくある発生パターンと解説

Exceeded maximum execution time は、Google Apps Scriptの開発において非常に頻繁に遭遇するエラーの一つです。主に以下のパターンで発生します。

  1. スプレッドシートの行数が多すぎる 数千〜数万行あるデータを forwhile ループで1行ずつ処理している場合。
  2. 外部APIへのリクエストを大量に繰り返している UrlFetchApp.fetch() はネットワーク遅延を伴うため、ループ内で何回も呼び出すとすぐに数分が経過してしまいます。
  3. 無駄なセル読み書き(Read/Write)が多い ループの中で getActiveSheet().getRange().setValue() などを毎回実行していると、GASの実行速度が著しく低下します。一括取得(getValues)と一括書き込み(setValues)を使用することが基本ですが、それでもデータ量が多すぎる場合は上記のバッチ処理が必要です。

よくある質問 (FAQ)

Q1: 無料アカウントと有料アカウント(Google Workspace)で制限時間は違いますか?

A: はい、異なります。無料のGoogleアカウント(@gmail.com)では1回の実行あたり最大6分ですが、Google Workspace(有料版)のアカウントでは最大30分まで拡張されます。ただし、30分であっても大量データの場合はタイムアウトするリスクがあるため、バッチ処理の実装を推奨します。

Q2: 途中で中断した処理の「続き」から再開するにはどうすればよいですか?

A: 上記の修正コードのように PropertiesService を使用して現在の進捗(インデックスやID)をスクリプトプロパティに保存しておき、次回実行時にその値から読み込みを再開するのが一般的です。

Q3: トリガーが無限ループしてしまわないか心配です。

A: 処理がすべて完了した時点で props.deleteProperty('LAST_INDEX') を呼び出し、トリガーを削除(または完了判定を入れて新規トリガーを作成しないように)するロジックを必ず組み込んでください。これにより無限ループを防ぐことができます。

💡 このエラーを含む【Google Apps Script (GAS)エラー完全攻略ハンドブック】をnoteで公開中 →