アルアカ - Arcadia Academia

Arcadia Academiaは「エンジニアリングを楽しむ」を合言葉に日本のデジタル競争力を高めることをミッションとするテックコミュニティです。

Google Sheets APIで書き込みだけ403になる時のサービスアカウント権限の確認手順

Featured image of the post

「スクリプトからシートを読むのは通るのに、行を追記しようとすると 403 で落ちる」「キーもAPIの有効化も合っているはずなのに、書き込みだけ権限がないと言われる」「権限を直したつもりが、まだ同じエラーが出る」

サービスアカウントで Google Sheets API を使うとき、こうした「読めるのに書けない」詰まりはよく起きます。原因の多くは、シートの共有設定でサービスアカウントが「閲覧者」のままになっていることです。ただし、同じ 403 でも原因は他に2つあり、直す場所が違います。

この記事では、読み取りと書き込みの両方を試す確認コード、403 の原因の切り分け表、直し方、書き込み前に取っておくバックアップの手順が分かります。

💡
💡 30秒で要点
- 読み取りが通って書き込みだけ 403 なら、サービスアカウントの共有権限が「閲覧者」のことが多い
- 直し方は、シートの共有設定でサービスアカウントのメールアドレスを「編集者」にする
- 403 の文面が違えば別原因。API 未有効化とスコープ不足も同じ 403 で返る
- 書き込む前に、対象範囲の値をファイルへ保存してから追記する

目次を開く

症状:読み取りは通るのに書き込みだけ 403

典型的なエラーは、追記(values.append)や更新(values.update)で次のように返る形です。

HttpError 403 ... "The caller does not have permission"
status: PERMISSION_DENIED

同じスクリプトで values.get は成功します。読めているので、認証そのものは合っています。つまり「誰か」は通っていて、「その人に書く権限があるか」で止まっている状態です。

まず読み取りと書き込みを別々に試す

原因を推測する前に、読み取り・書き込みの結果を並べて見ます。次のコードは、対象シートの末尾セルへ1回だけ書いて、すぐ消す確認用です。

from google.oauth2 import service_account
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

KEY_FILE = "service-account.json"
SHEET_ID = "<スプレッドシートID>"
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]

creds = service_account.Credentials.from_service_account_file(KEY_FILE, scopes=SCOPES)
print("使っているアカウント:", creds.service_account_email)

sheets = build("sheets", "v4", credentials=creds).spreadsheets()

def try_call(label, fn):
    try:
        fn()
        print(label, "OK")
    except HttpError as e:
        print(label, "NG", e.status_code, e.reason)

try_call("読み取り", lambda: sheets.values().get(spreadsheetId=SHEET_ID, range="A1:A1").execute())
try_call("書き込み", lambda: sheets.values().update(
    spreadsheetId=SHEET_ID, range="Z1", valueInputOption="RAW",
    body={"values": [["権限テスト"]]}).execute())

書き込みに成功した場合は、テスト用のセル Z1 を手で消してください。出力の読み方は次のとおりです。

読み取り 書き込み 疑うもの
OK NG(The caller does not have permission) 共有権限が閲覧者
NG NG(同じ文面) そもそもシートが共有されていない、またはID違い
NG NG(insufficient authentication scopes) スコープが読み取り専用
NG NG(API has not been used ... or it is disabled) Sheets API が未有効

直し方:サービスアカウントを「編集者」で共有する

1. 共有すべきメールアドレスを確認する

上のコードが表示した creds.service_account_email が、共有先のアドレスです。キー JSON の中の client_email と同じ値です。

python3 -c "import json; print(json.load(open('service-account.json'))['client_email'])"

2. シートの共有設定で権限を「編集者」にする

スプレッドシートの右上「共有」を開き、上のアドレスを追加して権限を「編集者」にします。すでに追加済みなら、権限のドロップダウンを「閲覧者」から「編集者」に変えます。自分に共有権限がない場合は、シートのオーナーに依頼します。

3. もう一度確認コードを流す

書き込みが OK になれば完了です。共有の反映は通常すぐですが、変わらなければ数分待ってからやり直します。

スコープと API 有効化は別の直し方

共有権限が編集者なのに 403 が続くなら、切り分け表の他の行を確認します。

  • スコープ不足:SCOPES が spreadsheets.readonly になっていないか確認する。書き込みには https://www.googleapis.com/auth/spreadsheets が必要
  • API 未有効:クラウドコンソールで、サービスアカウントのプロジェクトの Google Sheets API を有効化する

書き込む前にスナップショットを保存する

権限が通った直後の最初の書き込みは、範囲や列の指定ミスで既存の値を壊しやすいタイミングです。書く前に、対象範囲の値を JSON で保存しておきます。

import json, datetime

RANGE = "Sheet1!A1:F1000"
before = sheets.values().get(spreadsheetId=SHEET_ID, range=RANGE).execute()
name = f"snapshot-{datetime.datetime.now():%Y%m%d-%H%M%S}.json"
with open(name, "w", encoding="utf-8") as f:
    json.dump(before, f, ensure_ascii=False, indent=2)
print("保存:", name)

シート名は自分の環境のものに置き換えてください。権限がまだ直っていない間は、追記する行を画面に出して手で貼り付ける運用にしておくと、作業を止めずに済みます。

まとめ

  • 読み取りが通って書き込みだけ 403 なら、サービスアカウントの共有権限が閲覧者のことが多い
  • 直し方は、client_email のアドレスをシートの共有設定で「編集者」にする
  • 同じ 403 でも、スコープ不足と API 未有効は文面が違う。切り分け表で確認する
  • 書き込む前に、対象範囲をスナップショットとして保存する

よくある質問(FAQ)

編集者にしたのに、まだ 403 が出ます

スコープが spreadsheets.readonly のままになっていないか確認してください。エラー文に「insufficient authentication scopes」が含まれていれば、共有ではなくコード側の設定です。

サービスアカウントを自分のアカウントの共有先に追加できません

共有先の欄に client_email のアドレスをそのまま入力します。組織の共有制限でドメイン外への共有が禁止されている場合は、管理者に許可を依頼します。

確認コードで書いたセルは消したほうがよいですか

はい。確認用の Z1 は残さず、手で消してください。

読み取り専用で十分な用途でも編集者にすべきですか

いいえ。読むだけなら閲覧者のままで足ります。書き込みが必要なシートだけ編集者にすると、誤書き込みの範囲を絞れます。

プログラミング学習でお悩みですか?

現役エンジニアがあなたの学習をマンツーマンでサポートします。

  • 学習の進め方がわからない
  • ポートフォリオの作り方を知りたい
  • 現場で使える技術を学びたい
まずは30分の無料相談

相談は完全無料・オンラインで気軽に

あなたを爆速で成長させるメンタリングプログラムはこちら

メンタープログラムバナー

学習・開発のお悩みは現役エンジニアに相談

メンタープログラムの詳細を見る

エンジニアの基礎学習ゲーム

プログラミング学習支援

無料相談はこちら