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

Google Classroom作业复制失败:Requested entity was not found错误排查

问题:Google Classroom作业复制时API调用失败,返回“Requested entity was not found”

在遍历源课堂课程作业并尝试复制到目标课堂时,虽能定位到目标作业(如“Activity 1: Introductions”),但调用Classroom.Courses.CourseWork.create API时失败,返回错误“Requested entity was not found”。请求解析该错误含义并排查问题。

错误日志

8:58:34 AM  Info    Activity 1: introductions
8:58:35 AM  Info    Error copying course content: GoogleJsonResponseException: API call to classroom.courses.courseWork.create failed with error: Requested entity was not found.
8:58:35 AM  Info    Error Stack: GoogleJsonResponseException: API call to classroom.courses.courseWork.create failed with error: Requested entity was not found.
    at CopyCourses6:113:46
    at Array.forEach (<anonymous>)
    at copyCourseContent6 (CopyCourses6:83:22)
    at __GS_INTERNAL_top_function_call__.gs:1:8

核心代码片段

var destinationCourseWorkResponse = fetchDataWithBackoff(function() {
  return Classroom.Courses.CourseWork.list(destinationCourseId ,  { courseWorkStates: ["PUBLISHED", "DRAFT"] });
});
Logger.log("Destination CourseWork Response: " + JSON.stringify(destinationCourseWorkResponse));
var destinationCourseWork = destinationCourseWorkResponse && destinationCourseWorkResponse.courseWork;

var destinationMaterialsResponse = fetchDataWithBackoff(function() {
  return Classroom.Courses.CourseWorkMaterials.list(sourceCourseId, { courseWorkMaterialStates: ["PUBLISHED", "DRAFT"] });
});
Logger.log("Destination Materials Response: " + JSON.stringify(destinationMaterialsResponse));
var destinationMaterials = destinationMaterialsResponse && destinationMaterialsResponse.material;

var sourceCourseWorkResponse = fetchDataWithBackoff(function() {
  return Classroom.Courses.CourseWork.list(sourceCourseId);
});
if (sourceCourseWorkResponse && sourceCourseWorkResponse.courseWork) {
  var courseWork = sourceCourseWorkResponse.courseWork;

  if (courseWork && courseWork.length > 0) {
    courseWork.forEach(function(item) {
      if (item) {
        // Check if courseWork exists in destination (using fetched data)
        var courseWorkExists = destinationCourseWork && destinationCourseWork.some(function(destItem) {
          return destItem.title === item.title;
        });

      //  if (!courseWorkExists) {
          var newCourseWork = {
            title: item.title,
            description: item.description,
            state: item.state,
            dueDate: item.dueDate,
            dueTime: item.dueTime,
            maxPoints: item.maxPoints,
            workType: item.workType,
            materials: item.materials,
            assigneeMode: item.assigneeMode,
            assignment: item.assignment,
            multipleChoiceQuestion: item.multipleChoiceQuestion,
            scheduledTime: item.scheduledTime,
            creationTime: item.creationTime,
            updateTime: item.updateTime,
            alternateLink: item.alternateLink,
            //courseWorkType: item.courseWorkType,
          };
          if (item.topicId && topicMap[item.topicId]) {
            newCourseWork.topicId = topicMap[item.topicId];
          }
          Logger.log(newCourseWork.title)
          Classroom.Courses.CourseWork.create(newCourseWork,destinationCourseId);

指数退避函数

// Function to fetch data with exponential backoff
function fetchDataWithBackoff(apiCall) {
  var maxRetries = 5;
  var retryDelay = 1000; // Initial delay in milliseconds
  for (var retry = 0; retry < maxRetries; retry++) {
    try {
      var response = apiCall();
      Logger.log("API call successful after " + (retry + 1) + " retries.");
      return response;
    } catch (e) {
      Logger.log("API call failed (retry " + (retry + 1) + "): " + e.toString());
      if (retry < maxRetries - 1) {
        Utilities.sleep(retryDelay);
        retryDelay *= 2; // Double the delay for the next retry
      } else {
        Logger.log("API call failed after max retries.");
        return null; // Return null if all retries fail
      }
    }
  }
  return null; // Should not reach here, but included for safety
}

错误含义解析

“Requested entity was not found”表示API请求中引用的某个实体不存在。在CourseWork.create场景下,通常是以下几种情况:

  • 目标课程ID(destinationCourseId)无效或不存在
  • 作业中关联的topicId无效(即使做了topicMap映射,可能映射后的ID在目标课程中不存在)
  • 作业材料(materials)中引用的资源(如Drive文件)在当前授权下不可访问或已被删除

排查步骤

  • 验证目标课程ID有效性:调用Classroom.Courses.get(destinationCourseId)确认是否能获取到课程信息,若失败则说明ID错误或权限不足。
  • 检查Topic ID映射正确性:调用Classroom.Courses.Topics.list(destinationCourseId)获取目标课程所有Topic,对比映射后的ID是否在列表中。
  • 清理作业中的无效字段:移除newCourseWork中的creationTime、updateTime、alternateLink字段,这些是Google Classroom自动生成的,创建时传入可能引发异常。
  • 检查作业材料可用性:确认作业包含的materials对应的资源在目标课程授权范围内可访问,私有文件需先复制到共享目录或调整权限。
  • 确认API权限:检查脚本是否拥有Classroom.CourseWork.create权限,授权范围需包含https://www.googleapis.com/auth/classroom.coursework.students或https://www.googleapis.com/auth/classroom.coursework.me。
  • 恢复存在性检查:取消注释if (!courseWorkExists)判断,避免重复创建作业引发异常。

内容的提问来源于stack exchange,提问作者Class Admin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 16:57:25