深夜のプロダクション環境でのクラッシュ
午前2時。15の異なるリージョナルタブから1つのマスターダッシュボードにデータを統合するスクリプトを実行しています。昨日はすべて正常に動作していましたが、今は実行ログがエラーの赤色で染まっています。スクリプトは特定のエラーで行き詰まりました:
Exception: The target range is too small to receive the source data.
このエラーは、copyTo() メソッドがジオメトリ(形状)の不一致を検出したときに発生します。ソースデータが100行10列であるのに対し、コピー先を99行10列として定義している場合、Google Apps Script はデータの損失を防ぐために実行を停止します。大きなブロックを小さなコンテナに押し込むことを拒否するのです。
10秒でできる解決策
最も確実な解決策は、コピー先の左上のセルのみを指定することです。フルレンジではなく単一のセルを指定すると、Apps Script は必要なスペースを自動的に計算します。ディメンション(次元)について不平を言うことなく、隣接するセルにデータを展開してくれます。
ハードコードされた範囲を避ける:
// ソースデータが11行に増えると失敗します
sourceRange.copyTo(targetSheet.getRange("A1:C10"));
代わりにアンカーセルを使用する:
// 1行でも10,000行でも動作します
sourceRange.copyTo(targetSheet.getRange("A1"));
なぜエラーが発生するのか
Range オブジェクトを copyTo(destination) のパラメータとして渡すと、エンジンは厳格なバリデーションを実行します。そのコピー先の範囲に複数のセルが含まれている場合(例:A1:B20)、スクリプトはディメンションがソースと完全に一致することを期待します。
この失敗を引き起こす典型的なシナリオは以下の通りです:
- 動的な増加: コードを書いたときにはなかった3つの新しい列がソースシートに追加された。
- オフバイワンエラー:
getLastRow()を使用したが、ヘッダー行によって総数が変わることを忘れていた。 - 結合されたセル: ターゲットエリア内の1つの結合セルによって、エンジンが利用可能な幅を実際よりも小さいと誤認してしまう。
3つの信頼できる解決策
1. アンカーセル法(ベストプラクティス)
開始セルだけを指定するのが最もクリーンな方法です。データが何行何列を占めているかを計算する必要がなくなります。これは単純なデータ移行に理想的です。
function consolidateData() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sourceSheet = ss.getSheetByName("Monthly_Report");
const targetSheet = ss.getSheetByName("Archive");
const sourceRange = sourceSheet.getDataRange();
const destCell = targetSheet.getRange("A1");
// エンジンが自動的に拡張を処理します
sourceRange.copyTo(destCell);
}
2. 動的なディメンションの一致
コピーの直後にその特定の領域に条件付き書式やデータバリデーションを適用する場合などは、フルレンジを定義する必要があるかもしれません。その場合は、ソース自身のディメンションを使用してターゲットを構築します。
function copyWithExplicitRange() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const source = ss.getSheetByName("Source").getRange("B2:F15");
const targetSheet = ss.getSheetByName("Target");
// ソースの正確なサイズを取得する
const rows = source.getNumRows();
const cols = source.getNumColumns();
// 完全に一致するコピー先を構築する(1行目、1列目から開始)
const targetRange = targetSheet.getRange(1, 1, rows, cols);
source.copyTo(targetRange);
}
3. setValues() を使用する場合
書式なしで生データのみを貼り付けるために setValues() を使用する場合、ルールが変わります。copyTo() とは異なり、setValues() メソッドは正確な一致を要求します。setValues() に単一のセルを渡すことはできません。範囲のディメンションを計算しなければ、スクリプトは毎回失敗します。
// setValues の正しい使い方
const data = sourceRange.getValues();
targetSheet.getRange(1, 1, data.length, data[0].length).setValues(data);
修正を確認する方法
以下の3つのステップでスクリプトの回復性をテストしてください:
- ログを確認する: Apps Script の実行ログを開きます。赤い Exception テキストがなく「実行完了」メッセージが表示されていることを確認します。
- 行数を比較する: ソースが1,250行ある場合、コピー先も1,250行で終わっていることを確認します。
- ストレステスト: ソースにダミーデータを手動で10行追加し、スクリプトを再実行します。アンカーセル法を使用していれば、手動の介入なしに増加分を処理できるはずです。
隠れた落とし穴
- 保護された範囲: コピー先の1つのセルでも保護されている場合、制限されたスペースに「拡張」できないため、スクリプトが範囲サイズエラーを報告することがあります。
- 1,000万セルの制限: Google スプレッドシートはワークブックあたり1,000万セルに制限されています。コピー操作によってこの制限を超えると、一般的な範囲エラーが発生する可能性があります。
- フィルタ表示: フィルタが有効なシートにデータをコピーすると、予期しない結果を招くことがあります。スクリプトは、一部の行が非表示になっていても、基盤となるグリッドを認識します。

