本サイトはアフィリエイト広告(A8.net/もしもアフィリエイト/アクセストレード等)を利用しています
GASよく出るエラー10選と解決コード集|辞書代わりに使える完全版
📂 GAS入門

GASよく出るエラー10選と解決コード集|辞書代わりに使える完全版

📅 ⏱ 読了 約14分 ✍️ 凛

💡 本記事には広告(アフィリエイトリンク)が含まれる場合があります。

「実行ボタンを押したら赤い文字が出た。英語で読めない」 「昨日は動いたのに、今日は動かない」 「undefined ってなに?どこを直せばいいの?」

GASを触り始めた最初の1週間、私はこのエラー地獄で何度も手が止まりました。公式ドキュメントは正確ですが、「そもそも用語がわからない」という段階では読み進められません。

この記事は、私が実際に踏み抜いたエラーを辞書として引ける形にまとめたものです。エラーメッセージで検索して飛んできた方は、目次から自分のメッセージを探してください。

その前に:エラーメッセージの読み方

GASのエラーは、たいてい次の3つの情報を持っています。

TypeError: Cannot read properties of undefined (reading 'age')
    at getUser(コード:3:25)
部分意味
TypeErrorエラーの種類(型の問題)
Cannot read properties of undefined (reading 'age')何が起きたか(undefinedのageを読もうとした)
at getUser(コード:3:25)どこで(getUser関数の3行目25文字目)

読む順番は「どこで」→「何が」→「種類」です。まず行番号に飛んでください。エラーの9割は、指された行の変数の中身を見れば分かります。

直す前に、まず中身を見る

[エラーが出た] → [メッセージ全文をコピー] → [指された行へ飛ぶ]
 → [その行で使っている変数を console.log で出す] → [直す] → [再実行]

いきなり書き換えると、たいてい別のエラーが増えます。console.log を挟んで状態を目で見るのが結局いちばん速い道です。

console.log(typeof data, JSON.stringify(data));  // 型と中身を同時に確認

自動実行(トリガー)で出たエラーは、エディタ左メニューの**「実行数」**から履歴とログを確認できます。手動実行のログは実行のたびに下に出ます。


1. TypeError: Cannot read properties of undefined

いちばん多いエラーです。「存在しないものの、中身を読もうとした」ときに出ます。

function getUser() {
  const data = { name: '太郎' };
  console.log(data.profile.age);   // profile が無いので落ちる
}

なぜ起きるかdata.profileundefinedundefined.age は読めません。

解決:オプショナルチェーン(?.)と、既定値(??)で守ります。

console.log(data.profile?.age ?? '未設定');

スプレッドシートの値やAPIの応答は「あるはず」と思っていても空のことがあります。外から来た値は必ず疑うのが基本姿勢です。

2. ReferenceError: XXX is not defined

変数名のタイプミスか、宣言忘れです。

function run() {
  const sheetName = '売上';
  console.log(sheetname);   // 小文字のnで別物になっている
}

解決:スペルを確認します。GASエディタは打ち間違いを赤い波線で教えてくれるので、保存前に一度エディタ上の警告を見る癖をつけると激減します。

なお、関数名を間違えると「XXX is not a function」になります。似ていますが原因は同じ「その名前のものが無い」です。

3. Exception: Service Spreadsheets failed / シートがnull

シート名を変更した、シートを消した、他の人が同時に編集している、などで起きます。

const sheet = SpreadsheetApp.getActive().getSheetByName('売上');
sheet.getRange('A1').setValue(1);   // シートが無いと sheet は null

解決:取得直後に必ずチェックを入れます。

const sheet = SpreadsheetApp.getActive().getSheetByName('売上');
if (!sheet) throw new Error('「売上」シートが見つかりません。シート名を確認してください');

エラーメッセージを自分の言葉にしておくと、半年後の自分が助かります。

4. Exception: Authorization is required(承認が必要です)

権限をまだ許可していないときに出ます。初回実行では必ず出るので、故障ではありません。

解決手動で1回実行して承認します。

  1. エディタで関数を選んで実行
  2. アカウントを選ぶ
  3. 「このアプリはGoogleで確認されていません」→「詳細」→「(プロジェクト名)に移動」
  4. 内容を確認して「許可」

自分で書いた未公開のスクリプトなので、この警告表示は正常です。トリガーの自動実行では承認ダイアログが出せないため、必ず手動実行を先に済ませてください。

また、スクリプトに新しいサービス(例:Gmail送信)を追加すると、権限の範囲が変わるのでもう一度承認が必要になります。「昨日まで動いていたのに」の正体はこれのことがあります。

5. Exception: Service invoked too many times for one day

1日あたりの上限に達しました。無料アカウントの主な上限は次のとおりです。

機能1日の上限(目安)
メール送信100通
URL取得(UrlFetchApp)20,000回
トリガーの合計実行時間90分

解決:まず「本当にその回数が必要か」を疑います。ループの中でメールを1通ずつ送っているなら、1通にまとめるだけで解決することがほとんどです。

どうしても回数が必要なら、処理を日をまたいで分割します。上限は変更されることがあるので、最新は公式のQuotasページで確認してください。

6. Exception: Script took too long(実行時間6分の壁)

1回の実行が6分を超えると強制終了されます。GASでいちばん有名な制限です。

function heavyTask() {
  const sheet = SpreadsheetApp.getActiveSheet();
  for (let i = 1; i <= 10000; i++) {
    sheet.getRange(i, 1).setValue(i);   // 1万回の書き込み=間違いなく落ちる
  }
}

解決A:まとめて読み書きする(まずこれ)

const values = [];
for (let i = 1; i <= 10000; i++) values.push([i]);
sheet.getRange(1, 1, values.length, 1).setValues(values);   // 書き込みは1回だけ

シートとのやり取り(getValuesetValue)は1回ごとに時間がかかります。配列にためて最後に1回が鉄則で、これだけで数十倍速くなることも珍しくありません。

解決B:続きから再開できるようにする

どうしても量が多いときは、どこまで終わったかを記録して分割します。

function chunkedRun() {
  const props    = PropertiesService.getScriptProperties();
  const startRow = Number(props.getProperty('startRow') || '1');
  const sheet    = SpreadsheetApp.getActiveSheet();
  const data     = sheet.getDataRange().getValues();
  const batch    = data.slice(startRow, startRow + 1000);

  batch.forEach(function (row) { processRow(row); });

  const next = startRow + 1000;
  if (next >= data.length) {
    props.deleteProperty('startRow');    // 最後まで終わったらリセット
    console.log('全件完了');
  } else {
    props.setProperty('startRow', String(next));
    console.log(next + '行目まで完了');
  }
}

7. SyntaxError: Unexpected token

括弧やカンマの閉じ忘れなど、文法の間違いです。この場合はコードが1行も実行されません。

解決:エディタが指す行の少し上を疑ってください。閉じ括弧の不足は、実際のミス位置より後ろの行でエラーになることが多いためです。

私は初期に } をひとつ余分に書いていて、2時間溶かしたことがあります。インデント(字下げ)を揃えておくと、こういうミスが目で見つかるようになります。

8. Exception: Range not found

範囲の指定が不正です。getRange('A1:Z') のように行番号を省いた書き方や、行数・列数に0を渡したときに出ます。

// 空のシートだと getLastRow() が 0 になって落ちる
sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn());

解決:0にならないよう保険をかけます。

const lastRow = Math.max(sheet.getLastRow(), 1);
const lastCol = Math.max(sheet.getLastColumn(), 1);
sheet.getRange(1, 1, lastRow, lastCol);

「テスト時は動いたのに、まっさらなシートで落ちる」の典型パターンです。

9. TypeError: XXX.map is not a function

配列だと思っていた変数が、配列ではありませんでした。APIの応答が1件のときにオブジェクトで返る、というのがよくある原因です。

解決:配列に揃えてから使います。

const arr = Array.isArray(result) ? result : [result];
arr.map(function (item) { return item.name; });

同じ理由で forEach is not a function も出ます。迷ったら console.log(Array.isArray(result)) で確かめてください。

10. Exception: Rate Limit Exceeded / 一時的な通信エラー

外部APIを短時間に叩きすぎたときや、相手側が一時的に不安定なときに出ます。

解決:待ち時間を倍にしながら再挑戦します(指数バックオフ)。

function fetchWithRetry(url, retries) {
  retries = retries || 3;
  for (let i = 0; i < retries; i++) {
    const res = UrlFetchApp.fetch(url, { muteHttpExceptions: true });
    if (res.getResponseCode() === 200) return res;
    Utilities.sleep(1000 * Math.pow(2, i));   // 1秒 → 2秒 → 4秒
  }
  throw new Error('取得に失敗しました:' + url);
}

muteHttpExceptions: true を付けておくと、エラー応答でも例外にならず、ステータスコードと本文を自分で確認できます。原因の切り分けが一気に楽になるので、外部APIを叩くときは常に付けておくのがおすすめです。


よくある「そもそも」の失敗3つ

失敗1:エラーメッセージを読まずに検索する

「GAS エラー」で検索するより、メッセージ全文をそのまま検索するほうが圧倒的に速く答えに着きます。英語のままで大丈夫です。

失敗2:保存せずに実行する

編集しただけで実行すると、古いコードが動きます。GASエディタは自動保存されますが、反映が一拍遅れることがあります。実行前に Ctrl+S(Macは ⌘+S)を癖にしてください。

失敗3:トリガーで動かす関数にgetActiveSpreadsheetを使う

手動では動くのに、トリガーだと落ちる——その原因の大半がこれです。トリガー実行時は「開いているシート」が存在しないため null になります。

// ❌ トリガーでは動かないことがある
const ss = SpreadsheetApp.getActiveSpreadsheet();

// ✅ IDで明示的に開く
const ss = SpreadsheetApp.openById('スプレッドシートのID');

運用するなら:失敗をメールで知らせる

自動実行は静かに失敗します。気づいたら1週間動いていなかった、というのは本当によくあります。

function safeRun(fn, name) {
  try {
    fn();
  } catch (e) {
    GmailApp.sendEmail(
      Session.getActiveUser().getEmail(),
      '【GAS】' + name + ' でエラー',
      e.message + '\n\n' + (e.stack || '')
    );
    throw e;   // 実行履歴にも失敗として残す
  }
}

function main() {
  safeRun(dailySummary, '日次集計');
}

あわせて、トリガーの設定画面で**エラー通知を「今すぐ通知を受け取る」**にしておいてください。この2つで「静かに死んでいた」がなくなります。

エラーと付き合えるようになると起きること

エラーに慣れてくると、こんな変化がありました。

  • 使い回せる自分用のコード断片が手元に溜まる
  • エラーを見た瞬間に「ああ、あれだな」と当たりが付くようになる
  • 人が書いたコードの不具合も直せるようになる

私はエラーと解決策を1行メモに残していきました。3か月後には、同じところで困っている人に説明できるようになっていました。エラーは覚えるものではなく、記録するものだと思います。

まとめ

  • エラーは「どこで → 何が → 種類」の順に読む
  • 直す前に console.log変数の中身と型を見る
  • undefined 系は ?.?? で守る
  • 6分の壁は「まとめて読み書き」でほぼ解決する
  • トリガーで動かす関数では getActiveSpreadsheet() を使わない
  • 自動実行には失敗通知を必ず付ける

エラーは、コードが「ここが違うよ」と教えてくれている状態です。次のエラーに出会ったら、またこの記事に戻ってきてください。

関連記事