Владелец Google-таблицы нажимает кнопку, запускает меню или меняет ячейку — автоматизация работает. Другой редактор выполняет те же действия, но ничего не происходит, появляется запрос доступа либо ошибка Authorization required. Причина обычно не в самой таблице, а в контексте выполнения Google Apps Script: от чьего имени запущен код, какой тип триггера используется и какие OAuth-разрешения выданы этому аккаунту.
Исправление начинается с определения точки входа. Функция из пользовательского меню, простой onEdit, устанавливаемый триггер, формула в ячейке и web app имеют разные правила. Замена одного механизма другим наугад может открыть лишний доступ к данным или заставить все действия выполняться от имени владельца.
Сначала определите, как запускается скрипт
- пользователь выбирает пункт пользовательского меню или нажимает рисунок-кнопку;
- функция вызывается как формула в ячейке;
- срабатывает простой триггер onOpen(e) или onEdit(e);
- используется installable trigger на открытие, редактирование, изменение или отправку формы;
- код запускается по времени;
- таблица обращается к web app через doGet(e) или doPost(e);
- функцию вызывает другой скрипт, API или внешняя интеграция.
Запишите имя функции, тип запуска, аккаунт пользователя, роль в файле и точное время сбоя. Затем откройте раздел Executions в Apps Script и найдите соответствующий запуск. Если записи нет, событие не дошло до функции; если запись есть, анализируйте статус, пользователя и исключение.
Почему у владельца работает, а у других пользователей — нет
Пользователь не выдал необходимые OAuth-разрешения
Bound-скрипт, запущенный вручную из таблицы, обычно действует от пользователя за клавиатурой. Владелец уже подтвердил доступ к Sheets, Drive или Gmail, а коллега запускает функцию впервые. Если интерфейс не показывает корректный authorization flow или пользователь отклонил часть granular permissions, вызов сервиса завершится ошибкой.
Простой триггер пытается вызвать сервис с авторизацией
Простые onOpen и onEdit работают в ограниченном режиме и не могут использовать службы, которым нужна авторизация. Код может казаться исправным при ручном запуске из редактора, но падать при реальном редактировании таблицы. Для задач с Gmail, внешними файлами или расширенными сервисами нужен installable trigger либо другой осознанный сценарий.
Installable trigger создан не тем аккаунтом
Устанавливаемый триггер запускается с разрешениями пользователя, который его создал, даже если событие вызвал другой редактор. Если триггер создан бывшим сотрудником, потерял авторизацию или не имеет доступа к целевой папке, автоматизация перестает работать для всех. При этом уведомление об ошибке может получить только владелец триггера.
Изменение выполнено скриптом или API
Редактирование ячейки пользователем и запись через Apps Script или Sheets API — разные события. Устанавливаемые триггеры не обязаны срабатывать от программных изменений. Если коллега использует импорт, форму или другой скрипт, ожидаемый onEdit может вообще не запускаться.
Недостаточно прав к файлу, диапазону или связанному ресурсу
Пользователь может редактировать таблицу, но не иметь доступа к другой таблице, папке Drive, календарю или защищенному диапазону. Проверяйте каждый ресурс, который открывается по id. Доступ к исходной таблице не наследуется автоматически внешними файлами.
Web app развернут с неподходящим execute as
Web app может выполняться от имени развернувшего приложение или от имени пользователя, который его открыл. Это влияет на доступные файлы и необходимость индивидуальной авторизации. Кроме того, deployment ограничивает круг пользователей: только владелец, домен, вошедшие пользователи или иной разрешенный вариант.
Google Workspace блокирует сервис или приложение
Администратор домена может ограничить Drive API, сторонние приложения, внешние OAuth-приложения или sensitive scopes. У владельца из одного домена скрипт работает, а у подрядчика с другим аккаунтом блокируется политикой. Такую ошибку нельзя надежно исправить повторным запросом доступа внутри кода.
Пошаговая диагностика
- Воспроизведите сбой под отдельным тестовым пользователем с такой же ролью, не используя личные данные.
- Откройте Executions и определите, был ли запуск, какой тип события указан и чем он завершился.
- Сравните ручной запуск функции и реальный триггер: одинаковая функция может иметь разный AuthMode.
- Проверьте, кто создал installable trigger и имеет ли этот аккаунт действующий доступ ко всем ресурсам.
- Посмотрите список Project OAuth Scopes и выясните, какие из них не выданы пользователю.
- Проверьте роль пользователя в таблице, доступ к связанным файлам и защищенным диапазонам.
- Если используется web app, проверьте активный deployment, access и execute as, а не только исходный код.
- Сверьте ограничения Workspace у администратора домена и статус используемых API.
- Проверьте квоты и журнал ошибок: сбой по лимиту может совпасть со входом другого пользователя.
Не выводите OAuth token, содержимое документов и email пользователей в общий журнал. Для диагностики достаточно execution id, типа запуска, функции, статуса, номера строки и обезличенного идентификатора ресурса.
Как исправить ручной запуск из меню или кнопки
Функция, которую пользователь запускает осознанно, должна корректно проводить его через авторизацию и сообщать о недостающем доступе. Проверьте, что меню создается для редакторов, а функция не зависит от активного листа, выделения или локали владельца без проверки.
- ограничьте scopes минимально необходимым набором;
- обработайте ситуацию, когда пользователь выдал только часть разрешений;
- покажите понятное сообщение вместо пустого catch;
- проверяйте существование листа и диапазона по стабильному id или имени;
- не используйте личный My Drive владельца как скрытое общее хранилище.
Когда заменить простой триггер на устанавливаемый
Если onEdit должен обращаться к сервису, требующему авторизации, простой триггер не подходит. Создайте installable trigger из доверенного рабочего аккаунта, документируйте его владельца и настройте контроль ошибок. Помните: он выполняется от создателя, поэтому фактический пользователь события не должен автоматически получать права этого аккаунта.
function handleEdit(e) { if (!e || !e.range) return; // Validate spreadsheet, sheet, range and new value. // Do not trust a cell value as a file ID or recipient. // Make the operation idempotent before external side effects. }Не создавайте одинаковый installable trigger при каждом открытии таблицы. Сначала проверьте существующие triggers, иначе одно редактирование начнет выполнять функцию несколько раз и создавать дубли писем или строк.
Если скрипт работает как web app
Определите, чьи данные должен видеть web app. Режим выполнения от владельца удобен для централизованной автоматизации, но требует строгой проверки вызывающего пользователя и входных параметров. Режим выполнения от активного пользователя лучше изолирует права, однако каждый пользователь должен авторизовать нужные scopes.
- проверьте URL актуального deployment, а не тестовый адрес /dev;
- после изменения кода создайте новую версию deployment, если выбран версионный выпуск;
- не передавайте OAuth token в клиентский JavaScript;
- проверяйте доступ к каждой операции на серверной стороне;
- учитывайте несколько одновременно авторизованных Google-аккаунтов в браузере.
Надежная работа с общими файлами
Если автоматизация принадлежит команде, храните рабочие таблицы и связанные файлы в общем диске или другом управляемом пространстве, подходящем вашей организации. Критический trigger не должен зависеть от личного аккаунта сотрудника. Назначьте технического владельца, процедуру передачи и резервного ответственного.
Не полагайтесь на SpreadsheetApp.getActive() в фоновой задаче: у trigger может не быть ожидаемого активного интерфейса. Для связанных ресурсов используйте явные идентификаторы из проверенной конфигурации и перед выполнением проверяйте доступ.
Параллельные действия и дубли
Несколько редакторов могут изменить таблицу почти одновременно. Даже после исправления прав скрипт способен дважды создать документ, отправить письмо или обработать одну строку. Защитите критический участок lock-механизмом и храните признак завершенной операции.
- формируйте idempotency key из стабильного id строки и типа операции;
- не считайте цвет ячейки или текстовый статус надежной блокировкой;
- сначала фиксируйте состояние обработки, затем выполняйте внешний side effect;
- ошибку записывайте отдельно от завершенного статуса, чтобы повтор был контролируемым.
Как проверить исправление
- владелец и обычный редактор запускают функцию с ожидаемым результатом;
- пользователь только с просмотром не получает неразрешенную возможность изменения;
- новый пользователь проходит понятную авторизацию и выдает минимальные scopes;
- отказ от одного обязательного scope дает контролируемое сообщение;
- простой и устанавливаемый trigger тестируются отдельно;
- ручная правка и запись через API ведут себя согласно документированному сценарию;
- web app проверен в нужном execute as и под аккаунтом другого домена;
- два одновременных редактирования не создают дубли;
- ошибки видны в Executions и не содержат токенов или данных таблицы.
Типичные ошибки при ремонте
- выдать всем пользователям права владельца вместо исправления модели доступа;
- считать простой onEdit полноценным авторизованным процессом;
- создать installable trigger в личном аккаунте и не документировать владельца;
- ожидать onEdit после изменения ячейки другим скриптом или API;
- добавить широкие OAuth scopes на всякий случай;
- публиковать web app от имени владельца без проверки вызывающего пользователя;
- ловить все исключения пустым catch, из-за чего для коллег скрипт просто молчит.
Как предотвратить повторение проблемы
В документации проекта зафиксируйте точку входа каждой функции, effective user, требуемые scopes, владельца trigger, используемые файлы и поведение при ошибке. После добавления нового Google-сервиса проверяйте, не изменился ли набор разрешений, и проводите повторную авторизацию контролируемо.
Создайте тестовую таблицу и минимум два тестовых аккаунта с разными ролями. Проверка только под владельцем не выявляет основную часть проблем Apps Script с доступом и контекстом выполнения.
Когда нужна помощь с Google Apps Script
Если скрипт Google Sheets работает только у владельца, я могу определить реальный контекст выполнения, исправить scopes, триггеры, deployment и доступ к связанным файлам, а также добавить защиту от дублей. Для оценки пришлите тип запуска, текст ошибки из Executions, список используемых сервисов и обезличенный фрагмент кода без OAuth-токенов и данных таблицы.