instructure/canvas-lms · error · GraphQL::ExecutionError

Assignment not found

Error message

Assignment not found

What it means

create_comment_bank_item#get_assignment looks up the assignment via AbstractAssignment.assignment_scope_for_context(course).active.find(assignment_id); ActiveRecord::RecordNotFound is rescued and re-raised as 'Assignment not found'. The scope restricts to assignments visible in that course context, so mismatched course/assignment pairs also fail.

Solutions

  1. Confirm the assignment belongs to the same course passed as courseId and is active
  2. Check the id is in the scope: AbstractAssignment.assignment_scope_for_context(course).active.find(id) in console
  3. Use fresh assignment ids from the course's assignments query rather than cached values
  4. Verify shard/id format (legacy numeric vs relay id)

Example fix

// before
createCommentBankItem(input: { courseId: "1", assignmentId: "999" }) // assignment in course 2
// after
assignment = course.assignments.active.first
createCommentBankItem(input: { courseId: "1", assignmentId: assignment.id.to_s })
Defensive patterns

Strategy: validation

Validate before calling

const assignments = await canvas.get(`/api/v1/courses/${courseId}/assignments`)
if (!assignments.some(a => String(a.id) === String(assignmentId))) throw new Error('assignment not in this course or inactive')

Type guard

function belongsToCourse(a, courseId) { return a != null && a.course_id != null && String(a.course_id) === String(courseId) && !a.deleted_at }

Try / catch

try {
  await client.mutate({ mutation: CREATE_COMMENT_BANK_ITEM, variables: { courseId, assignmentId } })
} catch (e) {
  if (e.message.includes('Assignment not found')) {
    // verify course/assignment pairing, then refetch ids
  }
  throw e
}

Prevention

When it happens

Trigger: Calling createCommentBankItem with an assignmentId that doesn't belong to the given course, is deleted, is not in the context's assignment scope (e.g. subassignment/quiz type excluded), or a nonexistent id.

Common situations: Assignment id taken from a different course than the courseId supplied; assignment soft-deleted; wiki/LTI assignment types filtered out by assignment_scope_for_context; cross-shard id.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/75e742a19aca1b75. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/create_comment_bank_item.rb:50

    record = CommentBankItem.new(course:, user: current_user, comment: input[:comment], assignment:)
    verify_authorized_action!(record, :create)
    return errors_for(record) unless record.save

    { comment_bank_item: record }
  end

  private

  def get_course(course_id)
    Course.active.find_by(id: course_id).tap do |course|
      raise GraphQL::ExecutionError, I18n.t("Course not found") if course.nil?
    end
  end

  def get_assignment(assignment_id, course)
    AbstractAssignment.assignment_scope_for_context(course).active.find(assignment_id)
  rescue ActiveRecord::RecordNotFound
    raise GraphQL::ExecutionError, I18n.t("Assignment not found")
  end
end

View on GitHub (pinned to 1c9f0bb801)