GAS『DriveApp cannot be used in this context』の原因と対処法

GAS『DriveApp cannot be used in this context』の原因と対処法

「DriveApp はこのコンテキストでは使えません」は、現在の実行文脈(コンテキスト)が DriveApp のような“要認可サービス”を許可していないときに発生。代表例は「カスタム関数」「シンプルトリガー」「クライアント側(ブラウザ)からの直接実行」。実行主体・入口・スコープの一致を取り、必要ならインストール型トリガーやサーバ側関数へ寄せる。

エラーの意味と発生条件(まず押さえる)

・カスタム関数(=シートのセルに =MYFUNC())では DriveApp を呼べない(要認可サービス禁止)

・シンプルトリガー(onOpen/onEdit/onInstall 等)は権限制限下で実行されるため DriveApp が使えない

・HtmlService のクライアントJSや外部ページから直接 DriveApp を呼ぶことはできない(サンドボックス外)

・アドオン/実行API/ウェブアプリでも、実行主体やスコープ設定が合っていないと失敗

・共有ドライブや権限不足は別系統のエラーを誘発するが、文脈次第では同様に見える

最短の切り分け(どの文脈かを特定)

・“セルから呼んだのか”“トリガーで動いたのか”“ウェブアプリ経由か”をまず特定

・Executions/ログで入口(実行関数)と実行ユーザー(Session.getEffectiveUser)を確認

・「セル実行 or シンプルトリガー」なら、サーバ側の通常関数 or インストール型トリガーに移行を検討

対処1:カスタム関数では DriveApp を使わない(設計変更)

・カスタム関数は認可が必要なサービスを禁止。代わりに「別関数でデータ取得→シートへ書き込む」を onEdit/onOpen のインストール型トリガーで実行

・セルは“結果を表示するだけ”。I/O はイベント駆動のバッチに分離

サンプル:カスタム関数→インストール型トリガーに分離

// NG(セルから): =LIST_FILES("FOLDER_ID") のように DriveApp を直呼びは不可
function LIST_FILES(folderId) {
  // return DriveApp.getFolderById(folderId).getFiles(); // ← これがコンテキスト違反
}

// OK:ボタン/メニューやインストール型トリガーから実行する関数に分離
function listFilesToSheet(folderId, sheetId, sheetName) {
  const sh = SpreadsheetApp.openById(sheetId).getSheetByName(sheetName);
  const files = DriveApp.getFolderById(folderId).getFiles();
  const out = [];
  while (files.hasNext()) {
    const f = files.next();
    out.push([f.getName(), f.getId(), f.getUrl(), f.getSize()]);
  }
  sh.clearContents().getRange(1,1,out.length,4).setValues(out);
}

// メニューから実行できるように(手動 or トリガーで)
function onOpen() {
  SpreadsheetApp.getUi().createMenu('Tools')
    .addItem('フォルダ一覧を書き出す', 'runList')
    .addToUi();
}
function runList() {
  listFilesToSheet('YOUR_FOLDER_ID','YOUR_SHEET_ID','Data');
}

対処2:シンプルトリガー→インストール型トリガーへ

・onEdit/onOpen など“シンプルトリガー”は権限が弱い。DriveApp などは不可

・ScriptApp.newTrigger(…).onEdit()/timeBased() で“インストール型トリガー”を作り、作成者が認可を通す

サンプル:onEdit をインストール型へ置き換え

function job(e) {
  // DriveApp を安全に使える(作成者の認可で実行)
  const id = 'YOUR_FILE_ID';
  const name = DriveApp.getFileById(id).getName();
  SpreadsheetApp.getActive().getSheetByName('Log').appendRow([new Date(), name, e?.range?.getA1Notation()]);
}

function installOnEdit() {
  ScriptApp.newTrigger('job')
    .forSpreadsheet(SpreadsheetApp.getActive())
    .onEdit()
    .create();
}