{"record":{"id":"517d0e3092263c05","repo":"instructure/canvas-lms","slug":"not-found-create-discussion-topic","errorCode":null,"errorMessage":"Not found","messagePattern":"Not found","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/create_discussion_topic.rb","lineNumber":181,"sourceCode":"            dates:,\n            replies_required: checkpoint[:replies_required],\n            updating_user: current_user\n          )\n        end\n      end\n    end\n\n    discussion_topic.saved_by = :assignment if discussion_topic.assignment.present?\n    return errors_for(discussion_topic) unless discussion_topic.save!\n\n    if input.key?(:ungraded_discussion_overrides)\n      overrides = input[:ungraded_discussion_overrides] || []\n      update_ungraded_discussion(discussion_topic, overrides)\n    end\n\n    { discussion_topic: }\n  rescue Checkpoints::DiscussionCheckpointError => e\n    raise GraphQL::ExecutionError, e.message\n  rescue ActiveRecord::RecordInvalid\n    errors_for(discussion_topic)\n  rescue ActiveRecord::RecordNotFound\n    raise GraphQL::ExecutionError, \"Not found\"\n  end\n\n  def find_context(input)\n    context_id = GraphQLHelpers.parse_relay_or_legacy_id(input[:context_id], \"Context\")\n\n    if input[:context_type] == \"Course\"\n      Course.find(context_id)\n    elsif input[:context_type] == \"Group\"\n      Group.find(context_id)\n    else\n      nil\n    end\n  end\n","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/create_discussion_topic.rb#L163-L199","documentation":"CreateDiscussionTopic#resolve rescues ActiveRecord::RecordNotFound and raises GraphQL::ExecutionError \"Not found\". Inside resolve, this fires when context/lookup helpers (e.g. find_context or checkpoint-related lookups such as Assignment/SubAssignment records for checkpoint discussions) cannot find referenced records. It flattens all missing-record cases into one message.","triggerScenarios":"Creating a discussion topic with a context_id/context_type whose course or group no longer exists; checkpoint discussions referencing an assignment that was deleted; bad relay/legacy id format causing lookup failure during override or checkpoint setup.","commonSituations":"Course deleted or soft-deleted between UI load and submit; automation scripts using stale course ids; checkpoint feature flows where sub-assignments were removed by another teacher; SIS sync removing the course mid-operation.","solutions":["Confirm the context (course/group) id is valid and the course is not deleted before creating topics.","For checkpoint discussions, verify the parent assignment and sub-assignments still exist.","Use properly formatted Relay global ids or valid legacy numeric ids for context_id.","Re-fetch the course context in the UI if the session is long-lived."],"exampleFix":"// before\ncreateDiscussionTopic({contextId: storedCourseId, ...})\n\n// after\nconst course = await fetchCourse(storedCourseId)\nif (!course || course.workflowState === 'deleted') {\n  promptSelectCourse(); return\n}\ncreateDiscussionTopic({contextId: course.id, ...})","handlingStrategy":"validation","validationCode":"const course = await fetchCourse(contextId)\nif (!course || course.workflowState !== 'available') throw new Error('invalid context')","typeGuard":null,"tryCatchPattern":"try {\n  await createDiscussionTopic(input)\n} catch (e) {\n  if (/Not found/i.test(e.message)) promptReSelectContext()\n  else throw e\n}","preventionTips":["Validate course/group existence before topic creation.","For checkpoint topics, confirm assignments still exist.","Avoid hard-coded context ids in scripts and tests."],"tags":["graphql","record-not-found","discussions","checkpoints"],"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"}