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
- Confirm the submission id against the assignment's submissions in the current root account.
- Resolve the submission via the assignment/course path to confirm reachability.
- 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
- Pass submission ids obtained from the same account context in the current session
- Refetch submission before rubric save after long-idle UI
- Watch for deleted assignments cascading to submissions
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
- Rubric not found: #
- A course with that id does not exist
- ActiveRecord::RecordNotFound
- Allocation rule not found
- An assignment with that id does not exist
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 provisionalView on GitHub (pinned to 1c9f0bb801)