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

Course not found

Error message

Course not found

What it means

create_comment_bank_item#get_course uses Course.active.find_by(id: course_id) and raises 'Course not found' when nil. Because it uses the active scope, deleted or concluded courses are treated as missing even if the row exists.

Solutions

  1. Verify Course.active.find_by(id: course_id) returns a record in rails console
  2. Pass a valid legacy numeric course id in the correct shard
  3. Re-fetch course ids from the API if the course may have been deleted
  4. Ensure the user's GraphQL context resolves the course's root account

Example fix

// before
get_course(nil) // course_id not resolved from context_code
// after
course = Course.active.find_by(id: parsed_course_id)
raise GraphQL::ExecutionError, "Course not found" unless course
Defensive patterns

Strategy: validation

Validate before calling

let course
try { course = await canvas.get(`/api/v1/courses/${courseId}`) } catch { course = null }
if (!course || course.workflow_state !== 'available') throw new Error('Course not found or not active')

Type guard

function isActiveCourse(c) { return c != null && c.id != null && c.workflow_state === 'available' }

Try / catch

try {
  await client.mutate({ mutation: CREATE_COMMENT_BANK_ITEM, variables: { courseId } })
} catch (e) {
  if (e.message.includes('Course not found')) {
    // re-resolve courseId from the context code before retrying
  }
  throw e
}

Prevention

When it happens

Trigger: Calling createCommentBankItem with a courseId that is nil, deleted/concluded, nonexistent, or from a different shard/root account context.

Common situations: Client passes context code-derived id from a course since deleted; id format mismatch (relay id vs legacy id); course on another shard not resolved in the GraphQL context.

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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

Appendix: source

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

  argument :comment, String, required: true
  argument :course_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("Course")
  field :comment_bank_item, Types::CommentBankItemType, null: true

  def resolve(input:)
    course = get_course(input[:course_id])
    assignment = get_assignment(input[:assignment_id], course) if input[:assignment_id]
    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)