解決策:Apps Script でのエラー「Exception: The number of rows in the data does not match the number of rows in the range」の修正

intermediate📗 Google Sheets2026-06-23| Google Apps Script (V8 Engine), Google Sheets API

Error Message

Exception: The number of rows in the data does not match the number of rows in the range.
#apps-script#setValues#range#array-size#SpreadsheetApp

TL;DR: 即効の解決策

範囲の座標をハードコーディングするのはやめましょう。このエラーのほとんどは、データ配列の行数と、対象となるスプレッドシートの範囲が一致していないことが原因です。解決するには、データのサイズに合わせて範囲を自動的に定義するようにします。

// 避けるべき方法:データが増えるとエラーになります
// sheet.getRange("A1:B10").setValues(data);

// 推奨される方法:データのサイズに適応します
if (data && data.length > 0) {
  sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
}

根本原因

Google の setValues() メソッドは非常に厳密です。2次元配列と出力先の範囲が、完璧な長方形として一致することを想定しています。配列に500行のデータがあるのに、getRange() で指定した範囲が499行しかない場合、スクリプトは即座に停止します。

よくある失敗の原因は以下の通りです:

  • 静的な範囲指定: "A2:C100" のように範囲を固定しているが、データソースが101行に増えた。
  • 次元の不一致: [[1], [2], [3]] のような必要なネスト形式ではなく、[1, 2, 3] のような単純なリストを渡している。
  • 空のフィルタ結果: データセットをフィルタリングしたが、結果のセットがクリアした元の範囲よりも小さくなっている。

信頼性の高い解決策

1. 範囲サイズの動的指定

最終行や最終列を手動で計算するとバグの原因になります。代わりに、配列の length プロパティを使用してください。これにより、データに必要なスペースを正確にスプレッドシート上に確保できます。

function updateSheetSafely(data) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName("レポート");

  // データセットが空の場合のエラーを防ぐガード句
  if (!data || data.length === 0) return;

  const startRow = 1;
  const startCol = 1;
  const numRows = data.length;
  const numCols = data[0].length;

  // この範囲はデータのサイズに合わせて常に拡大・縮小します
  sheet.getRange(startRow, startCol, numRows, numCols).setValues(data);
}

2. 1次元配列から2次元配列へのマッピング

Apps Script では、["値 1", "値 2"] は単なるフラットなリストとして扱われ、グリッドとは見なされません。setValues() はこの形式を受け付けないため、データに「高さ」や「幅」を持たせるようにラップする必要があります。

// 1つの「行」として書き込む場合 (1行3列)
const rowData = [["値 1", "値 2", "値 3"]];
sheet.getRange(1, 1, 1, rowData[0].length).setValues(rowData);

// 1つの「列」として書き込む場合 (3行1列)
const flatArray = ["A", "B", "C"];
const colData = flatArray.map(item => [item]); // 結果: [["A"], ["B"], ["C"]]
sheet.getRange(1, 1, colData.length, 1).setValues(colData);

3. オフバイワン・エラー(1の誤差)のデバッグ

ループ内で配列を作成していると、最後に誤って空の行を追加してしまうことがよくあります。スクリプトがクラッシュする直前に console.log() を使用して次元を確認してください。これにより、スクリプトが実際に認識しているサイズが判明します。

console.log("配列の行数: " + data.length);
console.log("配列の列数: " + data[0].length);
// これらの数値が範囲と一致しない場合、スクリプトは失敗します。

修正の確認方法

スクリプトが本番環境で動作するか、以下の3点を確認してください:

  • 実行ログ: 緑色の「完了」チェックマークを確認します。「失敗」と表示される場合は、依然として次元が一致していません。
  • シートの境界: データの最終行を確認します。動的な範囲指定により、隙間を残したり誤ったセルを上書きしたりすることなく、データが完璧に収まっているはずです。
  • 負荷テスト: 1行のデータで実行し、次に1,000行で試してください。堅牢なスクリプトは、コードを変更することなく両方のケースを処理できます。

プロのヒント:「ゴーストデータ」を避ける

動的な範囲指定でクラッシュは防げますが、古いデータが残ってしまう可能性があります。新しいデータが10行で、古いデータが50行あった場合、setValues() は最初の10行しか上書きしません。レポートを綺麗に保つために、常に書き込み先の範囲を先にクリアしてください。

// 新しいデータを書き込む前にすべてクリアする
sheet.getRange(1, 1, sheet.getLastRow(), sheet.getLastColumn()).clearContent();
sheet.getRange(1, 1, data.length, data[0].length).setValues(data);

Related Error Notes