You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Google Calendar API Apps Script 问题排查:Google群组内单一用户触发'Error: Not Found: Skipping'报错

问题分析与解决方案:单个用户触发Calendar API "Not Found" 错误

错误原因拆解

你遇到的GoogleJsonResponseException: Not Found错误仅发生在单个用户身上,大概率和该用户的日历资源状态或权限配置有关,而非脚本逻辑的普遍问题。具体可能的原因包括:

  • 用户主日历资源不存在/不可用:Calendar.Events.list(user.getEmail(), params)默认访问用户的主日历(通常ID就是邮箱),但如果该用户的主日历被删除、账号被禁用/归档,或者主日历ID已变更(极少数情况),API就会返回"Not Found"。
  • 脚本无权限访问该用户的日历:你的脚本是通过运行账号的权限访问群组成员日历的,如果这个用户没有将主日历共享给脚本运行账号(比如团队管理员账号),或者仅设置了私有权限,API会因为无法定位到可访问的日历资源而返回错误。
  • 用户账号状态异常:比如用户已退出群组但未被移除,或者邮箱地址存在隐性格式问题(虽然群组返回的用户邮箱通常是有效的,但也不排除特殊场景)。

针对性解决方案

按照优先级尝试以下步骤:

  1. 验证用户账号与日历状态

    • 直接登录该用户的Google账号,确认主日历是否正常存在(打开Google Calendar,检查左侧"我的日历"列表里的默认日历)。
    • 确认该用户仍在目标Google群组中,且账号处于活跃状态(未被暂停/删除)。
  2. 修复权限配置

    • 让该用户将主日历共享给脚本的运行账号:打开日历设置 → 找到主日历 → 点击"添加人员",输入脚本运行账号的邮箱,授予查看所有事件的权限(无需编辑权限)。
    • 如果你是用团队共享账号运行脚本,确保该账号在群组中拥有足够权限访问成员信息与日历。
  3. 优化脚本中的日历ID获取逻辑
    避免直接使用user.getEmail()作为日历ID(极端情况下用户主日历ID可能不是邮箱),改用Calendar.CalendarList.list()获取用户的主日历ID:

    function findEvents(user, keyword, start, end, optSince) {
      let params = {
        q: keyword,
        timeMin: formatDateAsRFC3339(start),
        timeMax: formatDateAsRFC3339(end),
        showDeleted: true,
      };
      if (optSince) {
        params.updatedMin = formatDateAsRFC3339(optSince);
      }
    
      let pageToken = null;
      let events = [];
      let userCalendarId = null;
      try {
        // 获取用户的主日历ID
        const calendarList = Calendar.CalendarList.list({userId: user.getEmail()});
        userCalendarId = calendarList.items.find(item => item.primary)?.id || user.getEmail();
      } catch(e) {
        console.error('Failed to get calendar list for %s: %s; skipping', user, e.toString());
        return [];
      }
      do {
        params.pageToken = pageToken;
        let response;
        try {
          response = Calendar.Events.list(userCalendarId, params);
        } catch (e) {
          console.error('Error retriving events for %s, %s: %s; skipping', user, keyword, e.toString());
          continue;
        }
        events = events.concat(response.items.filter(function(item) {
          return shoudImportEvent(user, keyword, item);
        }));
        pageToken = response.nextPageToken;
      } while (pageToken);
      return events;
    }
    
  4. 修复脚本中的潜在bug
    顺便发现你的shoudImportEvent函数有个笔误:keyword.toLowerCase缺少了括号,应该是keyword.toLowerCase(),否则会导致事件过滤逻辑失效(因为你是在比较函数引用而非字符串):

    // 原错误代码
    if (event.summary.toLowerCase().indexOf(keyword.toLowerCase) < 0) {
      return false;
    }
    // 修复后
    if (event.summary.toLowerCase().indexOf(keyword.toLowerCase()) < 0) {
      return false;
    }
    
  5. 增强错误处理
    目前的错误处理只是跳过当前关键词的查询,你可以修改逻辑,当捕获到单个用户的日历访问错误时,直接跳过该用户的所有关键词处理,减少冗余日志:

    // 在sync函数的users.forEach循环中
    users.forEach(function(user) {
      let username = user.getEmail().split('@')[0];
      let userAccessible = true;
      KEYWORDS.forEach(function(keyword) {
        if (!userAccessible) return;
        let events;
        try {
          events = findEvents(user, keyword, today, maxDate, lastRun);
        } catch(e) {
          userAccessible = false;
          console.error('Skipping all keywords for %s due to calendar access error: %s', user, e.toString());
          return;
        }
        events.forEach(function(event) {
          importEvent(username, event);
          count++;
        });
      });
    });
    

内容的提问来源于stack exchange,提问作者Brooke Taylor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 21:18:11