本文へ移動
戻る
トラブルシュート2026-10-14 更新読了 5分

google.script.run の結果が null になるときは、Date が混じっていないかを見る

サーバーの関数でシートを読んで返したのに、画面の側には null しか届きません。 ログを見ると、値は入っています。この組み合わせのときは、まず日付を疑ってみてください。

google.script.run でサーバーとやりとりできる値には、型の決まりがあります。数値・真偽値・文字列・null と、それだけで組んだオブジェクトと配列です。Date は入っていません。

公式のガイドには、Date を渡そうとするとリクエストが失敗する、と書かれています。オブジェクトや配列の中に入っている Date も同じ扱いです。100行の表のどこか1セルに日付があるだけで、全体が届かなくなります。

失敗ハンドラではなく、成功ハンドラに null が届くことがある

公式の書き方は「失敗する(fail)」です。ところが実際には、withFailureHandler が呼ばれないことがあります。withSuccessHandler に null が届いた、という報告が Issue Tracker や Stack Overflow に上がっています。

エラーにならないので、原因に気づきにくくなります。成功ハンドラの中で null を受け取ったら、まず返した値に Date がないかを見てください。

見えていること 見るところ
ログには値があるのに、画面には null 返す直前の値に Date が入っていないか
日付の列を消すと届く 日付が原因。文字にして返す
一部の行だけのときに届く その行の範囲に日付のセルがないか

getValues() は、日付のセルを Date で返す

シートを getValues() で読むと、セルの中身に応じて数値・真偽値・Date・文字列のどれかが入ります。日付として入力されたセルは Date です。

getValues() のリファレンスには、Web アプリ向けの注意書きもあります。範囲に日付のセルがあると Web アプリへデータを返せないので、数値や文字列に変換してから返すように、という内容です。

読んだ結果をそのまま返している関数は、誰かがシートに日付の列を足しただけで、一覧が空になります。

返す前に、日付を文字にする

読んだ値を返す前に、Date だけを文字列に置き換えます。

function readRows() {
  const ss = SpreadsheetApp.openById(SHEET_ID); // SHEET_ID は自分の表の ID
  const tz = ss.getSpreadsheetTimeZone();
  const values = ss.getSheetByName('一覧').getDataRange().getValues();

  return values.map((row) =>
    row.map((v) => (v instanceof Date ? Utilities.formatDate(v, tz, 'yyyy-MM-dd') : v)),
  );
}

'一覧' はシートの名前に、'yyyy-MM-dd' は返したい形に置き換えてください。時刻まで要るなら 'yyyy-MM-dd HH:mm' のようにします。

getDisplayValues() を使う手もあります。セルに表示されているとおりの文字列で返ってくるので、Date は混じりません。ただ、数値も「1,200」のような表示の形で届きます。計算に使う列があるなら、上のように Date だけを置き換えるほうが扱いやすいです。

文字にするときのタイムゾーン

スクリプトとスプレッドシートは、別々にタイムゾーンを持っています。この2つが食い違うのはよくあるバグの原因だ、と公式のリファレンスにも書かれています。

上の例では ss.getSpreadsheetTimeZone() を使っています。シートに見えている日付と同じ日付を返すためです。Session.getScriptTimeZone() を使うと、スクリプト側の設定が違う場合に、日付が1日ずれて見えることがあります。

時刻まで正確にやりとりしたいなら、上の readRows() の formatDate を、UTC の ISO 8601 形式にする次の書き方に置き換えます。

const iso = Utilities.formatDate(v, 'UTC', "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

画面の側では new Date(iso) で Date に戻ります。toLocaleString() などで表示すると、ブラウザのタイムゾーンで出ます。

画面からサーバーへ送るときも同じ

決まりは往復どちらにもかかります。画面の側で作った Date を引数に入れて呼ぶと、こちらも届きません。日付は文字列のまま送ります。

// 画面の側。<input type="date"> の value は "2026-10-13" のような文字列
google.script.run.saveDue(dueInput.value);

saveDue はサーバー側の関数名に、dueInput は日付の入力欄に置き換えてください。サーバーの側で Date が要るときは、受け取ってから作ります。

ほかに届かなくなるもの

  • 関数
  • <form> 以外の DOM 要素(<form> は唯一の引数としてなら渡せます。戻り値にはできません)
  • 自分自身を参照しているオブジェクト

配列の中の undefined は、null に変わって届きます。エラーにはなりませんが、受け取った側で undefined と比べている処理は思ったとおりに動きません。