GAS『Insufficient Permissions』の原因と対処法
- 作成日 2025.10.20
- その他
Google Apps Scriptで「Insufficient Permissions(権限が不足しています)」が出るのは、実行主体に対象リソースのアクセス権がない、または要求スコープが不足/未認可だから。Drive/Sheets/Gmail/カレンダー等のサービス、共有ドライブや他ユーザー所有のファイル、ウェブアプリやトリガーの実行主体ずれ、Advanced ServicesやCloud API未有効化、組織ポリシーの制限など、発生箇所ごとの直し方をまとめる。
- 1. エラーの意味と発生条件(まず把握)
- 2. 誰の権限で動いているかを確認(実行主体の可視化)
- 3. スプレッドシート/Driveでの権限不足(ID・共有・ごみ箱・共有ドライブ)
- 4. Sheets/Gmail/Calendar等:要求スコープ不足(再認可/明示スコープ)
- 5. ウェブアプリの実行主体/アクセス設定の不整合
- 6. シンプルトリガーではなく“インストール型トリガー”に(権限の壁を回避)
- 7. Advanced Google services / Cloud API 未有効化
- 8. 組織ポリシー(信頼できるアプリ/スコープ制限)でブロック
- 9. リソース単位の共有漏れを自動検査(ファイル・シート名・範囲)
- 10. よくあるNG→OK(クイック修正集)
- 11. 失敗点を特定するための最小再現テンプレ
- 12. チェックリスト(上から順に潰す)
エラーの意味と発生条件(まず把握)
・対象リソース(スプレッドシート/ファイル/カレンダー/メール)に実行主体がアクセス権を持たない
・スクリプトが要求するOAuthスコープが不足(認可していない/マニフェスト未明示/権限を増やした)
・共有ドライブ(旧Team Drive)で、実行主体に閲覧/編集権限がない or ドメイン制限
・ウェブアプリ/トリガーの「実行するユーザー」と実際の権限が食い違う
・Advanced Google services や対応するCloud APIが未有効化
・組織の「信頼できるアプリ」やスコープ制御ポリシーでブロック誰の権限で動いているかを確認(実行主体の可視化)
// 実行主体(effectiveUser)とUI操作ユーザー(activeUser)をログ
function whoAmI() {
console.log({
effectiveUser: Session.getEffectiveUser().getEmail(),
activeUser: Session.getActiveUser().getEmail()
});
}
// ウェブアプリ/トリガー/ライブラリ経由で主体が変わることがあるので必ず確認スプレッドシート/Driveでの権限不足(ID・共有・ごみ箱・共有ドライブ)
// 典型NG:権限なし or ごみ箱 or 共有ドライブのアクセスなし
function openSheet(sheetId) {
// ここでInsufficient Permissions/アクセス拒否
const ss = SpreadsheetApp.openById(sheetId);
return ss.getName();
}
// 対処:IDの妥当性と共有状態を確認し、実行主体に権限を付与
function assertDriveFile(id) {
const f = DriveApp.getFileById(id); // 取得できなければ権限不足
console.log({name: f.getName(), trashed: f.isTrashed()});
// 必要に応じて編集者を付与(所有者権限がある場合のみ)
// f.addEditor('user@example.com');
}チェックポイント
□ URLではなく“IDのみ”をopenByIdに渡しているか
□ ファイルがごみ箱/共有ドライブに移動されていないか
□ 実行主体(whoAmIで確認)に閲覧/編集権があるか(共有設定)
□ 共有ドライブでは「コンテンツ管理者/編集者」以上か
Sheets/Gmail/Calendar等:要求スコープ不足(再認可/明示スコープ)
// 初回/権限追加後の“認可促し”関数(必要サービスを一度ずつ呼ぶ)
function authorizeOnce() {
const ss = SpreadsheetApp.getActive();
ss.getSheets()[0].getRange(1,1).setValue(new Date()); // spreadsheets スコープ
DriveApp.getFiles(); // drive スコープ
// GmailApp.getAliases(); // 必要なときだけ
console.log('authorized');
}
// appsscript.json に必要最小限のスコープを明示(例)
/*
{
"oauthScopes": [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive",
"https://www.googleapis.com/auth/script.external_request"
]
}
*/チェックポイント
□ エディタで authorizeOnce() を実行して同意ダイアログに承認したか
□ プロジェクト設定→スコープに想定のスコープが並んでいるか
□ スコープを増やしたのに再デプロイ/再認可していない、が起きていないかウェブアプリの実行主体/アクセス設定の不整合
// doGet/doPost は定義済みか
function doGet(e) {
return HtmlService.createHtmlOutput('OK');
}
/*
デプロイ時に確認:
・実行するユーザー:自分(推奨。自分にリソース権限があるなら確実)
・アクセスできるユーザー:自分のみ/全員/ドメイン内など要件に合わせる
・変更後は「新バージョンとしてデプロイ」必須(古い版のままだと権限食い違い)
*/典型NG→OK
× 実行主体を「アクセスするユーザー」にしており、そのユーザーにDrive権限がない
○ 「自分として実行」に変更し、所有者が対象ファイルの編集権を保持
シンプルトリガーではなく“インストール型トリガー”に(権限の壁を回避)
// シンプルトリガー(onEdit/onOpen)の制限でInsufficient Permissionsになりがち
// → インストール型トリガーに切り替え、作成者が認可
function job(e) {
// 要認可の処理(例:Drive/Calendar/Gmail)
const ss = SpreadsheetApp.getActive();
ss.getSheets()[0].appendRow([new Date(), 'trigger']);
}
function installOnEdit() {
ScriptApp.newTrigger('job').forSpreadsheet(SpreadsheetApp.getActive()).onEdit().create();
}チェックポイント
□ どのトリガーが失敗しているか(実行ログ)と、作成者が認可済みか
□ トリガー対象の関数名が最新か(改名後はトリガー再作成)
Advanced Google services / Cloud API 未有効化
[code]
/*
Sheets API / Drive API / Admin SDK などをコードから呼ぶ場合:
1) スクリプトエディタの「サービス」から対象サービスをON
2) 関連するCloud APIが有効化される(必要に応じCloud Console側を確認)
3) 初回呼び出しで認可ダイアログに同意
*/
function writeWithSheetsApi(sheetId) {
const body = { values: [[‘A’,’B’],[‘C’,’D’]] };
Sheets.Spreadsheets.Values.update(body, sheetId, ‘A1’, { valueInputOption: ‘USER_ENTERED’ });
}
[/code]
[code]
典型NG→OK
× ServicesをOFFのまま Sheets.Spreadsheets… を呼ぶ → Insufficient Permissions/Service not found
○ ServicesをON→初回実行で認可→成功
[/code]
組織ポリシー(信頼できるアプリ/スコープ制限)でブロック
[code]
/*
・Google Workspace 管理コンソールで第三者アプリ制限が有効だと、
ユーザーの同意だけではスコープを付与できない
対処:
・管理者に依頼して、該当デプロイのOAuthクライアントIDを「信頼できる」へ追加
・必要スコープ(spreadsheets/drive/gmail等)を許可リストへ
*/
[/code]
リソース単位の共有漏れを自動検査(ファイル・シート名・範囲)
[code]
// ファイル共有の検査(閲覧だけ/編集可 などの確認に利用)
function listEditors(fileId) {
const f = DriveApp.getFileById(fileId);
console.log({
name: f.getName(),
editors: f.getEditors().map(u => u.getEmail()),
viewers: f.getViewers().map(u => u.getEmail())
});
}
// シート存在チェック(見つからずnull→別のTypeErrorに化ける前に止める)
function getSheetSafe(id, name) {
const ss = SpreadsheetApp.openById(id);
const sh = ss.getSheetByName(name);
if (!sh) throw new Error(シートが見つかりません: ${name});
return sh;
}
[/code]
よくあるNG→OK(クイック修正集)
[code]
× 共有ドライブのスプレッドシートを、権限のない実行主体で編集
○ 実行主体に共有ドライブの編集権を付与 or ウェブアプリを「自分として実行」
× スコープ追加後に再デプロイ/再認可をしない
○ authorizeOnce() を実行→新バージョンとしてデプロイ
× シンプルトリガーからGmailApp/DriveAppを呼ぶ
○ インストール型トリガーに切替え、作成者が承認
× Advanced ServicesをOFFのまま利用
○ エディタのサービスON→Cloud API有効化→初回認可
× 別ドメイン/ゲストのアカウントで組織ポリシーにブロック
○ 管理者に「信頼できるアプリ」登録とスコープ許可を依頼
[/code]
失敗点を特定するための最小再現テンプレ
[code]
function diag() {
try {
const id = ‘YOUR_SHEET_ID’;
console.log(‘who’, Session.getEffectiveUser().getEmail());
const ss = SpreadsheetApp.openById(id); // Sheets/Drive権限
console.log(‘sheet’, ss.getName());
const files = DriveApp.getFiles(); // Drive権限確認
console.log(‘drive’, files.hasNext());
} catch (e) {
console.error(‘diag failed’, {msg: e.message, stack: e.stack});
throw e;
}
}
[/code]
チェックリスト(上から順に潰す)
[code]
□ whoAmI() で実行主体を確認(期待ユーザーか)
□ 対象ファイル/フォルダ/共有ドライブに実行主体の閲覧/編集権がある
□ スクリプトのスコープが十分(プロジェクト設定/マニフェスト)で、再認可済み
□ ウェブアプリは最新デプロイで、実行主体設定が要件と一致
□ シンプルトリガーで要認可APIを呼んでいない(インストール型へ)
□ Advanced Services と対応Cloud APIを有効化済み
□ 組織ポリシー(信頼できるアプリ/スコープ制御)に引っかかっていない
[/code]
-
前の記事
GAS『Authorization is Required』の原因と対処法 2025.10.17
-
次の記事
GAS『Trigger Already Exists』エラーの原因・対処まとめ 2025.10.20
コメントを書く