{"record":{"id":"5ed7b0f3cd1188ac","repo":"instructure/canvas-lms","slug":"not-found-create-submission","errorCode":null,"errorMessage":"not found","messagePattern":"not found","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/create_submission.rb","lineNumber":169,"sourceCode":"          ),\n          attribute: \"file_ids\"\n        )\n      end\n\n      upload_errors =\n        validate_online_upload(assignment, attachments, is_proxy: !!input[:student_id])\n      return upload_errors if upload_errors\n\n      submission_params[:attachments] =\n        Attachment.copy_attachments_to_submissions_folder(context, attachments)\n    when \"online_url\"\n      submission_params[:url] = input[:url]\n    end\n\n    submission = assignment.submit_homework(current_user, submission_params)\n    { submission: }\n  rescue ActiveRecord::RecordNotFound\n    raise GraphQL::ExecutionError, \"not found\"\n  rescue ActiveRecord::RecordInvalid => e\n    errors_for(e.record)\n  end\n\n  private\n\n  # TODO: move file validation to the model\n  def validate_online_upload(assignment, attachments, is_proxy: false)\n    if attachments.blank?\n      return validation_error(\n        I18n.t(\"You must attach at least one file to this assignment\"),\n        attribute: \"file_ids\"\n      )\n    end\n\n    # Probably a superfluous check considering how we retrieve the attachments\n    attachments.each { |attachment| verify_authorized_action!(attachment, :read) } unless is_proxy\n","sourceCodeStart":151,"sourceCodeEnd":187,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/create_submission.rb#L151-L187","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait gql(createSubmissionMutation, { input: { assignmentId: cachedId, ... } })\n// after\nconst a = await gql(getAssignment, { id: cachedId })\nif (!a) throw new Error('Assignment gone; refresh')\nawait gql(createSubmissionMutation, { input: { assignmentId: a._id, ... } })","handlingStrategy":"validation","validationCode":"const assignment = await gql(GET_ASSIGNMENT, { id: assignmentId })\nif (!assignment || assignment.state !== 'published') throw new Error('assignment missing or unpublished')","typeGuard":"function isSubmittableAssignment(a) { return a != null && a.state === 'published' && !a.lockedForUser }","tryCatchPattern":"try {\n  await gql(CREATE_SUBMISSION, { input })\n} catch (e) {\n  if (e.message === 'not found') { await refreshAssignments(); notifyAssignmentGone() }\n  else throw e\n}","preventionTips":["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."],"tags":["graphql","not-found","submissions","canvas-lms"],"backgroundTag":"record-not-found","analyzedSha":"1c9f0bb8013ed69c4f2efe11fd483025469b7e6c","analyzedAt":"2026-09-15T20:33:18.891Z","contentChangedAt":"2026-09-15T20:33:18.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T02:17:17.105Z"}