Google Sheets API batchUpdateが全体失敗したときの安全な復旧手順

複数の変更を一度に送ったあとエラーが返ると、「途中まで反映されたのでは」と心配になります。最初に区別したいのは、APIが失敗を明確に返したケースと、リクエストを送った後に通信が切れて結果を受け取れなかったケースです。

AIものさし編集部

まず「未適用」と「結果不明」を分ける

複数の変更を一度に送ったあとエラーが返ると、「途中まで反映されたのでは」と心配になります。最初に区別したいのは、APIが失敗を明確に返したケースと、リクエストを送った後に通信が切れて結果を受け取れなかったケースです。

Sheets APIのbatch requestでは、サブリクエストは適用前に検証されます。無効なリクエストが一つでもあれば、そのbatch全体が失敗し、変更は適用されません。したがって、明確な400系の入力エラーなど、APIがbatch不成立を返している場合は「一部だけ成功した」と決めつけて補修を始める必要はありません。問題のrequestを特定し、入力を直してから、意図したbatchを再送します。

一方、タイムアウトや接続切断では、サーバーが更新を適用した後に応答だけ失われた可能性を否定できません。この場合に同じ更新をすぐ再送すると、appendや新しいシート作成など、同じ操作を二重に行う危険があります。まず現在値を読み戻し、どの変更が反映されているかを確認してから次の操作を決めます。

本稿の前提はSheets API v4の spreadsheets.batchUpdate です。values APIの values.batchUpdate やApps Script、独自のラッパーを使っている場合、request形式やエラーの見え方が異なることがあります。エンドポイントと送信したJSONを最初に記録してください。

送信前に残す最小の記録

再試行を安全にするには、送信前の意図と送信後の観測を分離して残します。バッチごとに次を保存してください。

表は横にスクロールできます

項目記録する内容
対象spreadsheet ID、対象sheet ID、更新する範囲
実行実行ID、送信日時、実行者またはworker
入力request配列、field mask、更新前の重要セル値
期待成功時に成立するセル・シート・書式の状態
結果HTTP status、API error、response body、repliesの有無
再試行最初の実行ID、確認した範囲、次の実行ID

アクセストークン、サービスアカウント秘密鍵、OAuth refresh tokenなどの認証情報は記録に含めません。リクエスト本文に個人情報や機密値がある場合は、保存先と閲覧権限を限定し、ログへ丸ごと複製しないでください。

request配列の何番目かを追えるよう、アプリケーション側では各サブリクエストに連番または業務キーを付けたmanifestを作ります。Sheets API自身が任意のrequest IDを受け付けると仮定せず、ローカルのmanifestとrequest indexを対応させます。たとえば「request 2: タブの追加」「request 3: B4:D8更新」のように、順番と対象を説明可能にします。

明確なvalidation errorが返った場合

まずHTTP statusとGoogle API errorのmessage、status、detailsを保存します。responseにrequest indexが明記されないこともあるため、エラー文だけで失敗した位置を特定できない場合があります。送信したrequest配列を順に検査し、次のような誤りを見ます。

  • sheetIdが存在しない、または別のspreadsheetのIDを使っている

  • start/end row・column indexの境界が逆、範囲外、または対象sheetのgridより大きい

  • updateCellsのfield maskと更新値が一致しない

  • repeatCellの範囲やuserEnteredFormatのフィールド名が不正

  • addSheetで既存と重なるsheetIdや不正なプロパティを指定した

  • 数値・日付・数式などの値型が、列の期待と異なる

  • 一つ前のrequestが作るsheetやrangeを、後続requestが誤ったIDで参照している

「最後に追加した変更が悪い」と推測してその一つだけ直すのではなく、request配列全体を再検証します。複数の入力が同時に不正な場合もあります。修正後は、更新するセルとfield maskを小さく保ち、意図しない既存値・書式を置き換えないことを確認します。

batch内のrequestは配列の順で実行されます。先のrequestが作成するsheetなどに、後のrequestを依存させることはできます。ただし、batch全体が成功したときに限って一緒に適用されます。dependent requestのsheetId、range、field maskを、実行前にmanifest上で照合してください。

応答を受け取れなかった場合のreadback

通信断・クライアントtimeout・応答解析エラーでは、結果を「失敗」と決めず「不明」とします。再送前に、変更の種類に応じた範囲を読み戻してください。

表は横にスクロールできます

変更操作確認するもの再試行前の判断
固定範囲のセル更新対象範囲の全セル値・数式・必要な書式期待値と一致なら成功扱いにし、同じ書込みを重ねない。一部不一致なら現在値を比較して修復範囲を限定
addSheetspreadsheetのsheet一覧、sheetIdとtitle作成済みなら再作成しない。名前だけ同じでもsheetIdが異なる場合は別状態として確認
appendCells / 末尾追加追加行の業務キー、前後の行、実行ID同一業務キーや実行IDの行があるか調べ、二重追加を防止
書式変更対象範囲の実際の書式値だけで成功判定せず、必要な書式フィールドをreadback
複数操作各操作の完了条件と副作用操作ごとに状態を判定し、既適用分を飛ばして未適用分だけを処理

固定範囲への同じ値の設定は比較的冪等に設計しやすいものの、常に無条件で再送してよいわけではありません。途中で人や別workerが編集した可能性があるなら、送信前snapshotと現在値を比較し、他者の変更を上書きしないようにします。

読み戻しでは「更新対象セルだけ」ではなく、必要に応じて隣接範囲や数式・書式も見ます。行の挿入やソートなどで位置が変わる仕組みなら、行番号だけでは同一レコードと判定できません。Article IDや業務キーなど、安定した識別子で確認します。

エラー位置とrepliesの読み方

batchUpdateが成功すると、responseのrepliesはrequest配列と同じ順番で並びます。requestによっては返答内容がなく、その位置の要素が空になります。したがって、空のreplyを失敗と解釈してはいけません。HTTP成功とAPI responseを全体として確認し、request indexとreply indexを対応づけます。

反対に、batchがvalidationで失敗したときに、部分適用を前提に「成功したreplyまで反映済み」と扱うのは危険です。公式仕様上、一つでも無効なrequestがあればbatch全体が失敗します。まずエラーresponseと、通信が明確に失敗応答として届いたかを確認します。レスポンス自体が欠落している場合だけ、前節のreadbackで状態を確定します。

API wrapperがresponseの一部を捨てていると、Google APIから返ったstatusやdetailsが見えないことがあります。SDKやHTTP clientの例外を業務エラーへ変換する箇所を確認し、HTTP status、Google error body、ローカルrequest indexを失わないようにします。ただし記事の手順だけで特定SDKの例外形式を断定しないでください。使用中のclient libraryのversionに対応した公式referenceを確認します。

requestを小さく切り分ける方法

invalid requestの特定に時間がかかる場合、元データを保護したうえで、検証用コピーやテスト用spreadsheetでrequestを分割します。元の本番データに対して、原因探しのための試行錯誤を繰り返さないでください。

  1. 元のrequest配列、更新前snapshot、再現条件を保存する。

  2. 使用中のAPI endpointとrequest typeを確定する。

  3. 各requestを単独で構文・ID・range・field mask検証する。

  4. 検証環境で、依存関係のないrequest群へ分割して再現する。

  5. 原因requestを特定したら、必要な最小修正を行う。

  6. 元の業務上の原子性が必要なら、最終的には一つのbatchへ戻し、全体を再検証する。

  7. 実データへ送る直前に対象ID・範囲・更新前値を再確認する。

分割テストは原因特定のためであり、本来一体であるべき更新を本番で複数batchへ分ける提案ではありません。分割すると、別クライアントが間に編集できる時間が生まれ、望む整合性が失われる場合があります。

具体例:3セル更新の一つが不正

例として、A2に実行状態、B2に結果件数、C2に最終確認時刻を同一batchで設定する処理を考えます。これは説明用の架空データで、実際のAPI結果ではありません。

request 1はA2に文字列「complete」、request 2はB2に数値12、request 3は存在しないsheet IDのC2を更新しようとしています。Google APIがvalidation errorを返した場合、request 3だけが失敗してA2・B2が既に書かれたとは判断しません。batch全体が適用されないため、まず正しいsheet IDをmanifestとspreadsheet metadataから確認し、request 1〜3の全範囲を再点検して再送します。

ここでネットワークが切れ、HTTP応答を受け取れなかった場合は、同じ判断をしてはいけません。A2:C2をreadbackし、期待する3つの値が揃っているかを確認します。3つすべて一致なら、実行済みと記録します。すべて旧値なら、他者の編集がないことを確認したうえで再実行できます。一部だけ一致する状態なら、通常のbatch atomicityの想定と異なる原因(別操作・別worker・参照範囲誤りなど)を調べ、元値と現在値を比較して解決するまで自動再送しません。

再送前チェックリスト

次の項目をすべて確認してから再送します。

  • 対象spreadsheet IDとsheet IDがArticle IDや対象名称に合っている

  • API endpointが spreadsheets.batchUpdate か、別のbatch APIか確定した

  • 失敗が明確なAPI errorか、応答を失ったunknown outcomeか区別した

  • request配列の全件をID・range・型・field maskまで再検証した

  • 既存値を上書きしないための更新前snapshotがある

  • request indexと変更内容を照合できるmanifestがある

  • retryが二重append、二重作成、二重送信を起こさない

  • readbackで対象業務キーと更新後の期待状態を確認できる

  • 必要なreviewerが差分と影響範囲を確認した

  • 再送の実行IDと結果を記録できる

どれかが確認できなければ、再送を保留して不足情報を取得します。エラーを解消することより、対象範囲を正しく保ち、二重適用や別行への誤書込みを防ぐことを優先します。

作業記録に残す結果

復旧記録には、対象ID、request配列の要約、失敗分類、readback範囲、修正したrequest、再送有無、readback結果を残します。元のAPI responseと必要なログへの参照も保存しますが、認証情報は除外します。

記事や業務データの更新では、row順や配列indexをレコードIDの代わりにしません。たとえばArticle行を更新する場合は、対象Article IDを再検索し、IDと期待タイトルを照合してから対象セルを決めます。batchのindexはリクエストの順番を指すだけで、業務レコードの識別子ではありません。

最後に、処理後は書込み応答だけに頼らず、対象ID・セル・数式・statusを再取得して、期待状態と一致したことを記録します。readbackが一致しない場合は、成功扱いにせず、外部編集・誤ったsheet/range・数式計算待ちなどを切り分けます。通常のセル更新、書式変更、シート追加の完了条件を一つの「HTTP 200」にまとめず、操作ごとに定義してください。

公式情報と確認範囲

本稿はGoogle Sheets API v4のbatch requestと spreadsheets.batchUpdate の仕様を2026-10-15に確認し、atomic validation、request順序、response repliesの対応を説明しています。掲載した例は仕様を理解するための例であり、実際のスプレッドシートへAPI callを実行した結果ではありません。

出典・適用範囲

対象はGoogle Sheets API v4の spreadsheets.batchUpdate です。個々のclient libraryの例外型、認証scope、quota、values API、Apps Script固有の挙動は、本稿だけでは確定しません。実環境へrequestを送信したり、SDKを実行したりしていません。client libraryとendpointを特定した後、実装のerror mappingとreadback手順をテスト環境で確認してください。