使用ProjectApp2库批量创建GAS项目时出现Invalid ID错误排查
批量创建GAS项目时触发404 Invalid ID错误排查
问题背景
此前脚本运行完全正常,近一周开始报错。ProjectApp2库的更新项目、获取项目信息功能均正常,但在批量创建Google Apps Script(GAS)项目时触发404错误。测试脚本可正常运行,但主脚本执行时始终报错。
主脚本代码
/** * Создает проекты Google Apps Script из исходного кода, представленного в виде блобов (бинарных объектов). * Проекты создаются на основе данных, взятых из определенного листа. */ function создать_проекты_из_блоб_файлов__createProjectByBlob() { // Получение строк с названиями файлов и исходным кодом из листа SheetProject. // Исключение заголовков и пустых строк. const rows = Utils.values(SheetProject).filter(row => row[0] && row[0] != 'fileName'); // Формирование массива объектов с информацией о файлах скрипта. const scriptFilesInfo = rows.map(row => ({ name: row[0].toString(), code: row[1].toString() })); // Перевод информации о файлах скрипта в объекты Blob. const blobs = scriptFilesInfo.map(({ name, code }) => Utilities.newBlob(code, 'text/plain', name)); try { // Получение имен проектов для создания из листа, исключение заголовков и пустых строк. const data = Utils.values(SheetProject).filter(row => row[2] && row[2] !== 'projectName').map(row => row[2]); // Создание проектов с использованием функции ProjectApp2.createProjectByBlob // и данных о файлах скрипта. const creations = data.map((projectName) => { const projectCreationResult = ProjectApp2.createProjectByBlob(projectName, blobs); console.log(projectCreationResult); // Возвращаем объект с информацией о созданном проекте. return { url: `https://script.google.com/u/0/home/projects/${projectCreationResult.scriptId}/edit`, name: projectCreationResult.name, result: projectCreationResult }; }); // Логирование результатов создания проектов. console.log('Created projects:', JSON.stringify(creations, null, 2)); // Отображение результатов создания проектов пользователя. show(creations.map(({ url, name }) => [url, name])); } catch (error) { // Логирование ошибок в случае их возникновения. console.error('Error in createProjectByBlob function:', JSON.stringify({ error: error.toString() }, null, 2)); } };
错误信息
Error: {"error":{"code":404,"message":"Invalid ID","status":"NOT_FOUND","details":[{"@type":"type.googleapis.com/google.rpc.LocalizedMessage","locale":"en-US","message":"Invalid ID"}]}} updateProject @ Code.gs:218 createProject @ Code.gs:192 ProjectApp2.createProjectByBlob @ Code.gs:106 createProjectByBlob @ Code.gs:30 (функция без названия) @ testing.gs:24
测试脚本代码
function myFunction() { var json = { timeZone: "Asia/Tokyo", dependencies: { enabledAdvancedServices: [ { userSymbol: "Drive", serviceId: "drive", version: "v2", }, ], }, exceptionLogging: "STACKDRIVER", oauthScopes: ["https://www.googleapis.com/auth/drive"], }; const names = ['ghbdtn', 'gjrf', 'ljcdblfybz']; var blob = Utilities.newBlob(Utils.stringify(json), 'text/plain', "appsscript.json"); var blobs = [blob, Utilities.newBlob('// тесты', 'text/plain', 'ntcn')]; var res = names.map(name => ProjectApp2.createProjectByBlob(name, blobs)) // var res = ProjectApp2.updateProjectByBlob(projectId, blob); // If this is used, the Manifests in the existing project is updated. Logger.log(res); }
scriptFilesInfo示例
[ { name: 'appsscript.json', code: '{ "timeZone": "Asia/Yekaterinburg", "dependencies": { "libraries": [ { "userSymbol": "Trigger_lib", "libraryId": "1JqffuBy8rTgiUSudJYAbR8qokG-3MUSRClmyWRrY5S8", "version": 0, "developmentMode": true }, { "userSymbol": "Tg_lib", "libraryId": "1UbzKANMiHPB7PImDQDEXmJygTlvlDVSRe-kUV68JgTE", "version": 0, "developmentMode": true } ] }, "oauthScopes": [ "https://www.googleapis.com/auth/script.external_request", "https://www.googleapis.com/auth/script.scriptapp", "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/drive.file", "https://www.googleapis.com/auth/drive.readonly", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/spreadsheets.readonly", "https://mail.google.com/", "https://www.google.com/calendar/feeds", "https://www.google.com/m8/feeds", "https://www.googleapis.com/auth/admin.directory.group", "https://www.googleapis.com/auth/admin.directory.user", "https://www.googleapis.com/auth/documents", "https://www.googleapis.com/auth/drive", "https://www.googleapis.com/auth/forms.currentonly", "https://www.googleapis.com/auth/groups", "https://www.googleapis.com/auth/script.deployments", "https://www.googleapis.com/auth/script.deployments.readonly", "https://www.googleapis.com/auth/script.metrics", "https://www.googleapis.com/auth/script.processes", "https://www.googleapis.com/auth/script.projects", "https://www.googleapis.com/auth/script.projects.readonly", "https://www.googleapis.com/auth/spreadsheets", "https://www.googleapis.com/auth/userinfo.email" ], "exceptionLogging": "STACKDRIVER", "runtimeVersion": "V8" }' }, { name: 'settings', code: '/** * постоянные перменные */ const ss = SpreadsheetApp.openbyUrl(); const ssID = ss.getId(); // Получение доступа к свойствам скрипта const properties = PropertiesService.getScriptProperties(); /** * вспомогательные функции */ ' } ]
排查关键点
验证外部库ID有效性
主脚本的appsscript.json引用了两个第三方库,测试脚本无外部库依赖。错误栈显示在updateProject步骤失败,大概率是库ID无效(库被删除、权限变更或ID拼写错误)。手动在GAS编辑器中添加这两个库,确认是否能正常加载。修复代码语法错误
settings文件中SpreadsheetApp.openbyUrl();存在拼写错误,正确写法是openByUrl()(大写B),且缺少URL参数。这个语法错误会导致项目创建后初始化失败,返回无效ID。添加请求延迟避免限流
Google API有请求频率限制,批量创建项目时连续调用可能触发限流。测试脚本仅创建3个项目,主脚本创建数量更多时容易触发。在循环中添加Utilities.sleep(1000),每次创建后暂停1秒。优化表格数据读取逻辑
主脚本两次调用Utils.values(SheetProject)读取表格数据,可能存在数据不一致问题(比如读取期间表格被修改)。建议只读取一次数据,复用结果:// 优化后的数据读取 const allRows = Utils.values(SheetProject); const rows = allRows.filter(row => row[0] && row[0] != 'fileName'); const data = allRows.filter(row => row[2] && row[2] !== 'projectName').map(row => row[2]);
内容的提问来源于stack exchange,提问作者Antonio
相关产品推荐
相关产品推荐

