Google Script插件插入图片报错‘Action not allowed’排查求助
Google Sheets插件发布版插入Drive图片触发"Action not allowed"错误排查
问题背景
基于Cloud Platform开发Google Sheets插件,流程如下:
- 用户上传图片,插件将图片保存至用户Drive指定文件夹
- 日志显示
Logo file accessible: imagefilename.png,确认插件可正常访问该图片 - 插件尝试将图片插入文档时,触发
Action not allowed错误
核心代码
function insertLogoIntoDocument(body, userProperties) { const functionName = "insertLogoIntoDocument"; const functionNameError = `${functionName}_error`; basicLog(functionName, "LOGO_DEBUG_INIT", "Starting function"); try { // Check if body is valid if (!body) { basicLog(functionNameError, "LOGO_DEBUG_INVALID_BODY", "Document body is null or undefined"); return { isError: true, message: "Invalid document body provided" }; } const useCustomLogo = isUsingCustomLogo(); const logoTextElement = body.findText("<LOGO>"); if (useCustomLogo) { try { const logoImageId = userProperties.getProperty(LOGO_IMAGE_ID); basicLog(functionName, "LOGO_DEBUG_CUSTOM_DETECTED", "Checking for logo placeholder"); // Log whether the logo placeholder was found basicLog(functionName, "LOGO_DEBUG_SEARCH_RESULT", "Logo placeholder search completed"); if (logoTextElement) { try { const logoImage = DriveApp.getFileById(logoImageId); const logoBlob = logoImage.getBlob(); const logoElement = logoTextElement.getElement(); const logoPosition = logoElement.getParent().getChildIndex(logoElement); const logoParagraph = logoElement.getParent(); basicLog(functionName, "LOGO_DEBUG_CUSTOM_FILE_DATA", `Logo ID: ${logoImageId}, File: ${logoImage.getName()}, Blob: ${logoBlob.getBytes().length} bytes, Element: ${logoElement.getType()}, Parent: ${logoParagraph.getType()}, Position: ${logoPosition}` ); logoElement.setText(""); const inlineImage = logoParagraph.insertInlineImage(logoPosition, logoBlob); const originalWidth = inlineImage.getWidth(); const originalHeight = inlineImage.getHeight(); const aspectRatio = originalWidth / originalHeight; let targetHeight = 72; let targetWidth; try { const savedLogoSize = userProperties.getProperty(LOGO_SIZE_PROPERTY); basicLog(functionName, "LOGO_DEBUG_SIZE_RAW", "Processing saved logo size"); if (savedLogoSize) { targetHeight = parseInt(savedLogoSize, 10); if (isNaN(targetHeight)) { basicLog(functionName, "LOGO_DEBUG_SIZE_INVALID", "Using default size"); targetHeight = 72; } } else { basicLog(functionName, "LOGO_DEBUG_SIZE_MISSING", "Using default size"); targetHeight = 72; } basicLog(functionName, "LOGO_DEBUG_SIZE_FINAL", `Height: ${targetHeight}`); } catch (err) { const errorMessage = err.message || "No error message available"; const stackTrace = err.stack || "No stack trace available"; basicLog(functionNameError, "LOGO_DEBUG_SIZE_ERROR", `Error: ${errorMessage}, Stack: ${stackTrace}`); // Continue with default height if there's an error targetHeight = 72; } targetWidth = Math.round(targetHeight * aspectRatio); inlineImage.setHeight(targetHeight); inlineImage.setWidth(targetWidth); basicLog(functionName, "LOGO_DEBUG_INSERT_SUCCESS", `Height: ${targetHeight}, Width: ${targetWidth}`); return { isError: false, message: "Logo inserted successfully" }; } catch (err) { const errorMessage = err.message || "No error message available"; const stackTrace = err.stack || "No stack trace available"; basicLog(functionNameError, "LOGO_DEBUG_INSERTION_ERROR", `Error: ${errorMessage}, Stack: ${stackTrace}`); return { isError: true, message: "Error inserting logo: " + errorMessage }; } } else { try { const firstParagraph = body.getParagraphs()[0] ? body.getParagraphs()[0].getText() : "No paragraphs"; const secondParagraph = body.getParagraphs()[1] ? body.getParagraphs()[1].getText() : "No second paragraph"; basicLog(functionName, "LOGO_DEBUG_PLACEHOLDER_MISSING", `First paragraph: ${firstParagraph}, Second paragraph: ${secondParagraph}`); return { isError: true, message: "Logo placeholder not found in document" }; } catch (err) { const errorMessage = err.message || "No error message available"; const stackTrace = err.stack || "No stack trace available"; basicLog(functionNameError, "LOGO_DEBUG_TEMPLATE_ERROR", `Error: ${errorMessage}, Stack: ${stackTrace}`); return { isError: true, message: "Error checking document paragraphs" }; } } } catch (err) { const errorMessage = err.message || "No error message available"; const stackTrace = err.stack || "No stack trace available"; basicLog(functionNameError, "LOGO_DEBUG_HANDLING_ERROR", `Error: ${errorMessage}, Stack: ${stackTrace}`); return { isError: true, message: "Error handling logo: " + errorMessage }; } } else if (logoTextElement) { try { body.replaceText("<LOGO>", ""); basicLog(functionName, "LOGO_DEBUG_PLACEHOLDER_REMOVED", "No custom logo used"); return { isError: false, message: "Logo placeholder removed successfully" }; } catch (err) { const errorMessage = err.message || "No error message available"; const stackTrace = err.stack || "No stack trace available"; basicLog(functionNameError, "LOGO_DEBUG_REMOVAL_ERROR", `Error: ${errorMessage}, Stack: ${stackTrace}`); return { isError: true, message: "Error removing logo placeholder" }; } } // Default return if no conditions above were met return { isError: false, message: "No logo processing needed" }; } catch (err) { const errorMessage = err.message || "No error message available"; const stackTrace = err.stack || "No stack trace available"; basicLog(functionNameError, "LOGO_DEBUG_UNEXPECTED_ERROR", `Error: ${errorMessage}, Stack: ${stackTrace}`); return { isError: true, message: "Unexpected error in logo processing" }; } }
日志信息
LOGO_DEBUG_CUSTOM_FILE_DATA. Additional Info: Logo ID: "123456...", File: image_name.png, Blob: 158768 bytes, Element: TEXT, Parent: PARAGRAPH, Position: 0. LOGO_DEBUG_INSERTION_ERROR. Additional Info: Error: Action not allowed, Stack: Exception: Action not allowed at insertLogoIntoDocument (reportsGenerate/utils/logoHelper:38:47)
关键信息
- 已成功获取图片Blob(日志显示Blob字节数正常)
- 仅发布版报错,测试部署(Test Deployments)环境运行正常
- 已确认权限范围正确,且仅登录单个Google账号
- 尝试多种插入方式仍未解决
排查思路
- 核对发布版OAuth权限配置:测试部署与正式发布的权限范围可能存在差异,重新检查发布版OAuth consent screen的权限列表,确保
https://www.googleapis.com/auth/drive.file或对应权限已添加并标记为必要权限;确认用户在授权流程中已完整授予Drive相关权限。 - 验证文件与文档的权限上下文:检查目标文档和Drive图片的共享设置,确认插件运行的用户身份对两者均有编辑权限;可通过Drive API获取图片权限信息,验证插件身份的访问权限。
- 排查Workspace Marketplace限制:若插件通过Google Workspace Marketplace发布,查看控制台的审核状态与通知,确认是否触发了正式发布后的安全限制。
- 调整图片插入逻辑:尝试替换
insertInlineImage为appendImage等其他方法;调整操作顺序,先插入图片再清空占位符文本;或尝试将Blob转为Base64后插入,绕过直接引用Drive文件的限制。 - 确认发布版代码与执行环境:核对发布版代码与测试通过的代码是否完全一致;添加更详细的上下文日志,记录当前用户ID、文档ID、文件ID的权限状态,确认运行时身份正确性。
内容的提问来源于stack exchange,提问作者utphx
相关产品推荐
相关产品推荐

