{"record":{"id":"fe4ba7d7aced1bf9","repo":"instructure/canvas-lms","slug":"custom-grade-status-not-found-upsert","errorCode":null,"errorMessage":"custom grade status not found","messagePattern":"custom grade status not found","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/upsert_custom_grade_status.rb","lineNumber":50,"sourceCode":"\n      required_permission = custom_grade_status.new_record? ? :create : :update\n      unless custom_grade_status.grants_right?(current_user, session, required_permission)\n        raise GraphQL::ExecutionError, I18n.t(\"Insufficient permissions\")\n      end\n\n      if custom_grade_status.new_record?\n        InstStatsd::Statsd.distributed_increment(\"custom_grade_status.graphql.create\")\n      else\n        InstStatsd::Statsd.distributed_increment(\"custom_grade_status.graphql.update\")\n      end\n\n      if custom_grade_status.update(name: input[:name], color: input[:color])\n        { custom_grade_status: }\n      else\n        errors_for(custom_grade_status)\n      end\n    rescue ActiveRecord::RecordNotFound\n      raise GraphQL::ExecutionError, \"custom grade status not found\"\n    end\n  end\nend\n","sourceCodeStart":32,"sourceCodeEnd":54,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/upsert_custom_grade_status.rb#L32-L54","documentation":"This error is raised by the UpsertCustomGradeStatus GraphQL mutation when resolving fails with ActiveRecord::RecordNotFound. It means the custom_grade_status record the caller attempted to update (by id) does not exist, and the mutation converts that low-level exception into a user-facing GraphQL::ExecutionError.","triggerScenarios":"Calling the upsertCustomGradeStatus mutation with input whose :id refers to a CustomGradeStatus that has been deleted, belongs to a different course/root account (wrong shard), or whose id was mistyped, so the record lookup raises RecordNotFound inside resolve.","commonSituations":"Stale client caches referencing a deleted status; calling the mutation on a different shard than where the record lives; passing an id from a non-root-account context; scripts re-running upserts after cleanup tasks removed the record.","solutions":["Verify the custom grade status id exists (CustomGradeStatus.exists?(id)) before calling the mutation","Check you are hitting the correct root account/shard where the record lives","Re-fetch the list of custom grade statuses via the API to get fresh ids","Handle the error in the client by treating it as a deleted resource and re-syncing"],"exampleFix":"// before\nupdateCustomGradeStatus({ id: \"17\", name: \"Late\" })\n// after\nconst status = customGradeStatuses.find(s => s.id === \"17\")\nif (status) await updateCustomGradeStatus({ id: status.id, name: \"Late\" })","handlingStrategy":"try-catch","validationCode":"const exists = customGradeStatuses.some(s => s.id === inputId)\nif (!exists) throw new Error('custom grade status ' + inputId + ' not found')","typeGuard":null,"tryCatchPattern":"try {\n  const res = await client.mutate(UPSERT_CUSTOM_GRADE_STATUS, { id })\n} catch (e) {\n  if (e.message === 'custom grade status not found') {\n    await refetchStatuses() // treat as deleted, re-sync\n  } else throw e\n}","preventionTips":["Re-fetch status lists instead of caching ids across sessions","Confirm shard/root account before cross-account upserts","Handle RecordNotFound as a soft-delete signal in the client"],"tags":["graphql","record-not-found","mutation"],"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"}