instructure/canvas-lms · error · GraphQL::ExecutionError
not found
Error message
not found
What it means
CreateSubmission#resolve wraps assignment.submit_homework in a rescue of ActiveRecord::RecordNotFound, re-raised as 'not found'. submit_homework internally finds the assignment/attempt context, so an unknown assignment ID (or an ID the user may not see) triggers this before submission validation.
Solutions
- Re-fetch the assignment via GraphQL to confirm it exists and is published for this user.
- Ensure the ID belongs to the current course/shard and hasn't been deleted.
- Submit as an enrolled student with visibility of the assignment (hidden records raise not-found).
- Catch 'not found' in the client and refresh the assignment list before retrying.
Example fix
// before
await gql(createSubmissionMutation, { input: { assignmentId: cachedId, ... } })
// after
const a = await gql(getAssignment, { id: cachedId })
if (!a) throw new Error('Assignment gone; refresh')
await gql(createSubmissionMutation, { input: { assignmentId: a._id, ... } }) Defensive patterns
Strategy: validation
Validate before calling
const assignment = await gql(GET_ASSIGNMENT, { id: assignmentId })
if (!assignment || assignment.state !== 'published') throw new Error('assignment missing or unpublished') Type guard
function isSubmittableAssignment(a) { return a != null && a.state === 'published' && !a.lockedForUser } Try / catch
try {
await gql(CREATE_SUBMISSION, { input })
} catch (e) {
if (e.message === 'not found') { await refreshAssignments(); notifyAssignmentGone() }
else throw e
} Prevention
- Refetch assignments before submitting instead of trusting cached ids.
- Check lock/publish state for the submitting user.
- Never reuse assignment ids across beta/production shards.
When it happens
Trigger: Calling createSubmission with an assignmentId that doesn't exist, was deleted, lives on another shard, or is invisible to the submitting user; submitting to an unpublished assignment via a stale ID.
Common situations: Cached assignment IDs in an LTI tool after course copy; submitting to an assignment that was unpublished/deleted; cross-environment ID reuse between beta and production.
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/5ed7b0f3cd1188ac.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/mutations/create_submission.rb:169
),
attribute: "file_ids"
)
end
upload_errors =
validate_online_upload(assignment, attachments, is_proxy: !!input[:student_id])
return upload_errors if upload_errors
submission_params[:attachments] =
Attachment.copy_attachments_to_submissions_folder(context, attachments)
when "online_url"
submission_params[:url] = input[:url]
end
submission = assignment.submit_homework(current_user, submission_params)
{ submission: }
rescue ActiveRecord::RecordNotFound
raise GraphQL::ExecutionError, "not found"
rescue ActiveRecord::RecordInvalid => e
errors_for(e.record)
end
private
# TODO: move file validation to the model
def validate_online_upload(assignment, attachments, is_proxy: false)
if attachments.blank?
return validation_error(
I18n.t("You must attach at least one file to this assignment"),
attribute: "file_ids"
)
end
# Probably a superfluous check considering how we retrieve the attachments
attachments.each { |attachment| verify_authorized_action!(attachment, :read) } unless is_proxy
View on GitHub (pinned to 1c9f0bb801)