{"record":{"id":"24972ffb46d0e9b6","repo":"instructure/canvas-lms","slug":"record-not-found","errorCode":null,"errorMessage":"Record not found","messagePattern":"Record not found","errorType":"exception","errorClass":"GraphQL::ExecutionError","httpStatus":null,"severity":"error","filePath":"app/graphql/mutations/update_comment_bank_item.rb","lineNumber":40,"sourceCode":"  graphql_name \"UpdateCommentBankItem\"\n\n  argument :comment, String, required: true\n  argument :id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func(\"CommentBankItem\")\n\n  field :comment_bank_item, Types::CommentBankItemType, null: true\n\n  def resolve(input:)\n    record = CommentBankItem.active.find(input[:id])\n\n    verify_authorized_action!(record, :update)\n\n    record.comment = input[:comment]\n\n    return errors_for(record) unless record.save\n\n    { comment_bank_item: record }\n  rescue ActiveRecord::RecordNotFound\n    raise GraphQL::ExecutionError, I18n.t(\"Record not found\")\n  end\nend\n","sourceCodeStart":22,"sourceCodeEnd":43,"githubUrl":"https://github.com/instructure/canvas-lms/blob/1c9f0bb8013ed69c4f2efe11fd483025469b7e6c/app/graphql/mutations/update_comment_bank_item.rb#L22-L43","documentation":"UpdateCommentBankItem#resolve loads the CommentBankItem by id; when ActiveRecord::RecordNotFound bubbles out of resolve it is rescued at the end of the method and re-raised as GraphQL::ExecutionError 'Record not found'. The item either does not exist, was deleted, or is not visible to the current user's account scope.","triggerScenarios":"Calling updateCommentBankItem with an id of a deleted comment bank item, an id from another user/account, or a nonexistent id.","commonSituations":"Items deleted via UI while a client still holds their id; comment bank items are account-scoped so cross-account ids 404; stale caches in frontends after cleanup jobs.","solutions":["Re-query commentBankItems for the current user to get a valid id","Confirm the item was not deleted (CommentBankItem.active/exists?) and recreate it if needed","Ensure the id belongs to the same account/user context as the caller","Drop the update if the item was intentionally deleted"],"exampleFix":"// before\nmutation { updateCommentBankItem(input: {id: \"42\", comment: \"hi\"}) { ... } }\n// after\nquery { commentBankItemsConnection { nodes { id } } }\nmutation { updateCommentBankItem(input: {id: \"<valid-id>\", comment: \"hi\"}) { ... } }","handlingStrategy":"validation","validationCode":"const items = await canvasQuery(`query { commentBankItemsConnection { nodes { id } } }`);\nif (!items?.commentBankItemsConnection?.nodes.some(i => i.id === inputId)) throw new Error(`Comment bank item ${inputId} not found for this user; refresh list`);","typeGuard":"function itemExists(items, id) { return Array.isArray(items) && items.some(i => i?.id === id); }","tryCatchPattern":"try {\n  await updateCommentBankItem({ id, comment });\n} catch (e) {\n  if (/Record not found/.test(e.message)) {\n    // drop the item from the cache or recreate it\n  } else { throw e; }\n}","preventionTips":["Invalidate local comment-bank caches when items are deleted","Scope ids to the current user/account — items are account/user scoped","Treat 'Record not found' as a soft-delete signal, not a bug"],"tags":["graphql","activerecord","not-found"],"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"}