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

not found

Error message

not found

What it means

CreateSubmissionDraft#resolve wraps its work in a rescue for ActiveRecord::RecordNotFound and re-raises it as GraphQL::ExecutionError "not found". It fires when a record required to build the submission draft (typically the Submission via the given id, or an attachment/media record) cannot be found for the current context.

Solutions

  1. Verify the submissionId exists (Submission.active.find) and belongs to the current user before calling the mutation.
  2. Confirm any referenced file ids / media ids still exist.
  3. Check that the assignment and its submissions were not deleted.
  4. Read server logs for the RecordNotFound backtrace to identify the exact missing model.

Example fix

// before
createSubmissionDraft(input: { submissionId: staleId, ... })
// after
const sub = await apollo.query(gql`query($id: ID!){ submission(id:$id){ id } }`, { id: freshId })
if (sub) createSubmissionDraft(input: { submissionId: freshId, ... })
Defensive patterns

Strategy: try-catch

Validate before calling

const { data } = await client.query(gql`query($id: ID!){ submission(id: $id){ id } }`, { id })
if (!data?.submission) throw new SkipError('submission missing')

Type guard

function canDraft(submission) { return submission != null && !submission.deleted; }

Try / catch

try {
  await createSubmissionDraft(input)
} catch (e) {
  if (e.graphQLErrors?.some(g => g.message === 'not found')) {
    await refetchAssignment(); notifyUserStale();
  } else throw e;
}

Prevention

When it happens

Trigger: Calling createSubmissionDraft with a submissionId that does not exist, was soft-deleted, or is not visible to current_user; referencing file/media ids that were deleted before save!; cross-context ids.

Common situations: Stale client cache after the assignment/submission was deleted; student unenrolled so the submission lookup fails; attempt/submission state purged; using an id from another course or shard.

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/e0077d2a777676c4. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/create_submission_draft.rb:92

      submission_draft.resource_link_lookup_uuid = input[:resource_link_lookup_uuid]
    when "media_recording"
      submission_draft.media_object_id = input[:media_id]
    when "online_text_entry"
      submission_draft.body = input[:body]
    when "online_upload"
      file_ids = (input[:file_ids] || []).compact.uniq
      attachments = get_and_verify_attachments!(file_ids)
      verify_allowed_extensions!(submission.assignment, attachments)
      submission_draft.attachments = attachments
    when "online_url"
      submission_draft.url = input[:url]
    end

    submission_draft.save!

    { submission_draft: }
  rescue ActiveRecord::RecordNotFound
    raise GraphQL::ExecutionError, "not found"
  rescue ActiveRecord::RecordInvalid => e
    # activerecord validation is not robust to race condition
    #   multiple concurrent requests may penetrate activerecord validations
    #   and save dup records for a combination of submission_id and attempt
    # If it happened, following saves will be blocked by activerecord validation
    # Ideally, an unique index should be defined, but with many existing records,
    #   creating unique index may fail without cleaning data first.
    if submission_draft.present?
      submission_drafts = SubmissionDraft.where(
        submission: submission_draft.submission,
        submission_attempt: submission_draft.submission_attempt
      )
      if submission_drafts.count > 1 && !@retried
        @retried = true
        submission_drafts.where.not(id: submission_draft.id).destroy_all
        retry
      end
    end

View on GitHub (pinned to 1c9f0bb801)