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

Submission not found

Error message

Submission not found

What it means

save_rubric_assessment raises "Submission not found" when Submission.find_by(id:, root_account:) returns nil — the submission id is wrong or belongs to a different root account. Unlike find, find_by returns nil, so the mutation gives an explicit, friendly error before touching rubric data.

Solutions

  1. Confirm the submission id against the assignment's submissions in the current root account.
  2. Resolve the submission via the assignment/course path to confirm reachability.
  3. Check for shard/root_account mismatch in your session context.

Example fix

// before
submission = Submission.find_by(id: input[:submission_id], root_account:)
raise GraphQL::ExecutionError, 'Submission not found' if submission.nil?
// after
submission = assignment.submissions.find_by(id: input[:submission_id])
return validation_error('Submission not found for this assignment') unless submission
Defensive patterns

Strategy: validation

Validate before calling

const submission = assignment.submissionsConnection.nodes.find(s => s.id === submissionId)
if (!submission) throw new Error('Submission not found in this account')

Try / catch

try { await saveRubricAssessment({ submissionId, ... }) } catch (e) { if (e.message === 'Submission not found') showError('Submission unavailable; reload SpeedGrader') }

Prevention

When it happens

Trigger: submission_id omitted/zero/malformed, submission exists on another root account or shard, or submission hard-deleted (e.g. assignment deleted cascading submissions).

Common situations: Cross-account tool (LTI) passing ids from a different account; SpeedGrader tab left open after the submission was deleted; test-record ids used against production API.

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

Appendix: source

Thrown at app/graphql/mutations/save_rubric_assessment.rb:36

# with this program. If not, see <http://www.gnu.org/licenses/>.
#

class Mutations::SaveRubricAssessment < Mutations::BaseMutation
  argument :assessment_details, GraphQL::Types::JSON, required: true
  argument :final, Boolean, required: false, default_value: false
  argument :graded_anonymously, Boolean, required: true
  argument :provisional, Boolean, required: false, default_value: false
  argument :rubric_assessment_id, ID, required: false
  argument :rubric_association_id, ID, required: true
  argument :submission_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("Submission")

  field :rubric_assessment, Types::RubricAssessmentType, null: true
  field :rubric_association, Types::RubricAssociationType, null: true
  field :submission, Types::SubmissionType, null: true
  def resolve(input:)
    root_account = context[:domain_root_account]
    submission = Submission.find_by(id: input[:submission_id], root_account:)
    raise GraphQL::ExecutionError, "Submission not found" if submission.nil?

    association = RubricAssociation.find(input[:rubric_association_id])
    association_object = association.association_object

    assessment = association.rubric_assessments.find(input[:rubric_assessment_id]) if input[:rubric_assessment_id].present?

    # only check if there's no assessment object, since that's the only time
    # this param matters (find_asset_for_assessment)
    user_id = assessment.present? ? assessment.user_id : submission.user_id
    raise GraphQL::ExecutionError, "User ID blank - unable to determine user for assessment" if user_id.blank?

    # For a moderated assignment, submitting an assessment claims a grading
    # slot for the submitting provisional grader (or throws an error if no
    # slots remain).
    begin
      opts = {}
      provisional = input[:provisional]
      if provisional

View on GitHub (pinned to 1c9f0bb801)