instructure/canvas-lms · error · ActiveRecord::RecordNotFound
ActiveRecord::RecordNotFound
Error message
ActiveRecord::RecordNotFound
What it means
restore_deleted_discussion_entry raises a raw ActiveRecord::RecordNotFound from DiscussionEntry.find(input[:discussion_entry_id]) (or the explicit raise unless the user can :read the entry). Rails' find raises when the id does not exist, including soft-deleted/shard-mismatched rows; the explicit raise hides deleted entries from users without read rights.
Solutions
- Confirm the entry id exists: DiscussionEntry.where(id: id).exists?
- Verify current_user has :read and :update rights on the entry's context.
- Look up the entry through its discussion_topic within the accessible course to get a clearer error.
Example fix
// before
entry = DiscussionEntry.find(input[:discussion_entry_id])
// after
entry = DiscussionEntry.where(id: input[:discussion_entry_id]).first
return validation_error('Entry not found or inaccessible') unless entry&.grants_right?(current_user, session, :read) Defensive patterns
Strategy: try-catch
Validate before calling
// verify the entry is restorable and user has rights
const entry = await entryQuery(discussionEntryId)
if (!entry) return
if (!entry.viewerCanUpdate) showError('Insufficient Permissions') Type guard
function isEntryAccessible(entry, user) { return !!entry && !entry.deleted && entry.permissions.read === true && entry.permissions.update === true } Try / catch
try { await restoreDeletedDiscussionEntry({ id }) } catch (e) { if (e.message.includes('RecordNotFound')) showError('Entry no longer exists') else throw e } Prevention
- Hide restore actions for entries the user cannot read/update
- Check the restore_discussion_entry feature flag is on for the context
- Use GraphQL node queries (returns null) instead of ids that can 404
When it happens
Trigger: discussion_entry_id references a non-existent entry, an entry on a different shard, or an entry the current_user lacks :read rights on (e.g. not enrolled in the course).
Common situations: Clients restoring from a stale notifications/email link after the entry was hard-deleted; student attempting to restore another user's entry in a course they can no longer access.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- not found
- A course with that id does not exist
- Allocation rule not found
- An assignment with that id does not exist
- Assignment not found
AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15).
Data as JSON: /api/errors/e67b05262c6fc7da.
Report an issue: GitHub.
Appendix: source
Thrown at app/graphql/mutations/restore_deleted_discussion_entry.rb:31
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
class Mutations::RestoreDeletedDiscussionEntry < Mutations::BaseMutation
argument :discussion_entry_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("DiscussionEntry")
field :discussion_entry, Types::DiscussionEntryType, null: true
def resolve(input:)
entry = DiscussionEntry.find(input[:discussion_entry_id])
return validation_error(I18n.t("Insufficient Permissions")) unless entry.context.feature_enabled?(:restore_discussion_entry)
raise ActiveRecord::RecordNotFound unless entry.grants_right?(current_user, session, :read)
return validation_error(I18n.t("Insufficient Permissions")) unless entry.grants_right?(current_user, session, :update)
if entry.deleted?
entry.saving_user = current_user
entry.restore
{ discussion_entry: entry }
else
validation_error(I18n.t("Discussion entry is not deleted"))
end
end
end
View on GitHub (pinned to 1c9f0bb801)