instructure/canvas-lms · error · ArgumentError

quiz_submission not found in connection items

Error message

quiz_submission not found in connection items

What it means

PatchedArrayConnection computes quiz submission cursors using object identity (equal?) rather than id equality, because all versions of a quiz_submission in submission history share the same id but represent different attempts. If the node is not the exact in-memory object contained in items, this ArgumentError is raised.

Solutions

  1. Use the exact object instance from the connection's items array when requesting the cursor
  2. Re-fetch the whole connection (nodes + page info) in a single request instead of mixing objects
  3. Avoid re-loading the quiz submission by id; keep a reference to the original item
  4. If building custom nodes, insert them into the connection so identity holds

Example fix

// before
const qs = QuizSubmission.find(id)
const cursor = connection.cursorFor(qs) // new object, identity check fails
// after
const qs = connection.items.find(i => i.id === id)
const cursor = connection.cursorFor(qs)
Defensive patterns

Strategy: validation

Validate before calling

const inPage = connection.items.includes(node) // identity check, same as resolver
if (!inPage) throw new Error('quiz submission object not in this page')

Try / catch

try {
  const cursor = connection.cursorFor(node)
} catch (e) {
  if (/quiz_submission not found in connection items/.test(e.message)) {
    node = connection.items.find(i => i.id === node.id) // re-acquire exact instance
  } else throw e
}

Prevention

When it happens

Trigger: Requesting a cursor for a QuizSubmission object that is a different Ruby object instance than the one in items — a re-fetched copy, a deserialized version from simply_versioned, or a node loaded outside this connection's items array.

Common situations: Passing a freshly loaded QuizSubmission.find(id) instead of the object from the connection items; mixing objects across shards/requests; constructing quiz submission history nodes manually and then asking this connection for their cursors.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at app/graphql/patched_array_connection.rb:41

  # the index. Unfortunately submission histories are saved through versionable
  # which returns an array of submission histories that all share the same id,
  # and active record overrides the `==` method to check for equality based on
  # said id. When dealing with submissions, change the comparator to look at the
  # submitted_at time (what submission#submission_history is doing) instead of
  # by id so cursors don't break.
  def cursor_for_submission_node(submission)
    submission_idx = items.find_index { |i| i.submitted_at.to_i == submission.submitted_at.to_i }
    raise ArgumentError, "submission not found in connection items" unless submission_idx

    encode((submission_idx + 1).to_s)
  end

  def cursor_for_quiz_submission_node(quiz_submission)
    # Use object identity (not AR `==` which compares by id) since all items
    # in the array share the same quiz_submission id but represent different
    # attempts via simply_versioned deserialization.
    quiz_submission_idx = items.find_index { |i| i.equal?(quiz_submission) }
    raise ArgumentError, "quiz_submission not found in connection items" unless quiz_submission_idx

    encode((quiz_submission_idx + 1).to_s)
  end

  def cursor_for(item)
    return cursor_for_submission_node(item) if item.instance_of?(Submission)
    return cursor_for_quiz_submission_node(item) if item.instance_of?(Quizzes::QuizSubmission)

    super
  end
end

View on GitHub (pinned to 1c9f0bb801)