{"record":{"id":"447d19a2065db571","repo":"instructure/canvas-lms","slug":"assignment-not-found-assignment-id","errorCode":null,"errorMessage":"assignment not found: #{assignment_id}","messagePattern":"assignment not found: #(.+?)","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/update_assignment.rb","lineNumber":34,"sourceCode":"#\n# You should have received a copy of the GNU Affero General Public License along\n# with this program. If not, see <http://www.gnu.org/licenses/>.\n#\n\nclass Mutations::UpdateAssignment < Mutations::AssignmentBase::Mutation\n  graphql_name \"UpdateAssignment\"\n\n  argument :id, ID, required: true\n  argument :name, String, required: false\n  # most arguments inherited from AssignmentBase\n\n  def resolve(input:)\n    assignment_id = GraphQLHelpers.parse_relay_or_legacy_id(input[:id], \"Assignment\")\n\n    begin\n      @working_assignment = Assignment.find(assignment_id)\n    rescue ActiveRecord::RecordNotFound\n      raise GraphQL::ExecutionError, \"assignment not found: #{assignment_id}\"\n    end\n\n    # check permissions asap\n    raise GraphQL::ExecutionError, \"insufficient permission\" unless @working_assignment.grants_right? current_user, :update\n\n    update_proxy = ApiProxy.new(context[:request], @working_assignment, context[:session], current_user, in_app: context[:in_app])\n\n    # to use the update_api_assignment method, we have to modify some of the\n    # input. first, update_api_assignment doesnt expect a :state key. instead,\n    # it expects a :published key of boolean type.\n    # also, if we are required to transition to restored or destroyed, then we\n    # need to handle those as well.\n    input_hash = input.to_h\n    other_update_on_assignment = false\n    if input_hash.key? :state\n      asked_state = input_hash.delete :state\n      case asked_state\n      when \"unpublished\"","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/update_assignment.rb#L16-L52","documentation":"UpdateAssignment#resolve parses the input id and calls Assignment.find(assignment_id). A ActiveRecord::RecordNotFound is caught and converted to GraphQL::ExecutionError 'assignment not found: <id>'. The mutation aborts before any permission check or update is performed.","triggerScenarios":"Calling the updateAssignment mutation with an id that is not a valid Assignment (deleted assignment, wrong shard/context id, or an id that GraphQLHelpers.parse_relay_or_legacy_id resolved to a non-existent record).","commonSituations":"Client caches a stale assignment id after the assignment was deleted; tests/scripts hard-code ids from another environment; id confusion between Assignment and its discussion_topic/checkpoint sub-assignments.","solutions":["Re-fetch the assignment id from the course's assignments connection and retry","Confirm the assignment exists (Assignment.exists?) and is not deleted","Check you are hitting the correct Canvas shard/account for that id","If the assignment was deleted, restore it or drop the mutation"],"exampleFix":"// before\nmutation { updateAssignment(input: {id: \"999\", name: \"New\"}) { ... } }\n// after\n// resolve the id against the course first\nquery { course(id: 1) { assignmentsConnection { nodes { id name } } } }\nmutation { updateAssignment(input: {id: \"<existing-id>\", name: \"New\"}) { ... } }","handlingStrategy":"try-catch","validationCode":"const assignments = await canvasQuery(`query { course(id: $cid) { assignmentsConnection { nodes { id } } } }`, {cid});\nif (!assignments?.assignmentsConnection?.nodes.some(a => a.id === inputId)) throw new Error(`Assignment ${inputId} not found in course; aborting update`);","typeGuard":"function isKnownAssignment(node, id) { return node != null && node.id === id; }","tryCatchPattern":"try {\n  await updateAssignment({ id });\n} catch (e) {\n  if (/assignment not found/.test(e.message)) {\n    // refetch assignment list, surface stale-id error to user\n  } else { throw e; }\n}","preventionTips":["Refresh assignment ids after any delete/merge operations","Never reuse ids captured in another Canvas environment/shard","Include the course context in error logs to spot cross-course id use"],"tags":["graphql","activerecord","not-found"],"backgroundTag":"entity-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"}