instructure/canvas-lms · error · GraphQL::ExecutionError

Notification not found

Error message

Notification not found

What it means

The mutation could not find an AccountNotification with the supplied notification_id: AccountNotification.find_by(id: ...) returned nil. The ID may be wrong, already deleted (notifications expire), or a relay/global-ID was passed where a numeric ID is expected despite the relay_or_legacy_id prepare function accepting both.

Solutions

  1. Re-fetch current account notifications (query.account.notifications) and dismiss only IDs present in that response.
  2. Confirm the notification exists and is within start_at/end_at for the user's account: AccountNotification.find(id) in a rails console.
  3. Handle the error gracefully client-side: treat 'Notification not found' as success (already dismissed/expired) and refresh the list.
  4. Ensure the ID is either the numeric id or a valid relay base64 global ID for AccountNotification.

Example fix

// before
await client.mutate({ mutation: DISMISS, variables: { notificationId: cachedId } });
// after
const ids = (await client.query({ query: GET_NOTIFICATIONS })).data?.account?.notifications?.map(n => n._id) ?? [];
if (ids.includes(cachedId)) await client.mutate({ mutation: DISMISS, variables: { notificationId: cachedId } });
else refreshNotifications(); // already gone — ignore
Defensive patterns

Strategy: validation

Validate before calling

const notif = notifications.find(n => n._id === notificationId);
if (!notif) { refreshNotifications(); return; } // already gone
await dismiss(notificationId);

Type guard

const notificationExists = (notifications, id) => Array.isArray(notifications) && notifications.some(n => n && (n._id === id || n.id === id));

Try / catch

try { await dismiss(notificationId); }
catch (e) {
  if (e.graphQLErrors?.some(g => g.message === 'Notification not found')) await refreshNotifications(); // treat as already dismissed
  else throw e;
}

Prevention

When it happens

Trigger: Calling dismissAccountNotification with a notificationId that does not exist, was created for a different account/role the user cannot see, refers to a notification past its end_at (destroyed by AccountNotification.clean_up_old_notifications!), or a malformed ID string.

Common situations: Client cached a notification list that has since been cleaned up; double-dismiss race where the notification expired between list and dismiss; passing the wrong object's ID; hardcoding a dev-environment ID against production.

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


AI-assisted analysis of instructure/canvas-lms@1c9f0bb801 (2026-09-15). Data as JSON: /api/errors/37ee79280e06687e. Report an issue: GitHub.

Appendix: source

Thrown at app/graphql/mutations/dismiss_account_notification.rb:30

# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# 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/>.
#

module Mutations
  class DismissAccountNotification < BaseMutation
    argument :notification_id, ID, required: true, prepare: GraphQLHelpers.relay_or_legacy_id_prepare_func("AccountNotification")

    def resolve(input:, **)
      user = context[:current_user]
      raise GraphQL::ExecutionError, I18n.t("Must be logged in") unless user

      notification = AccountNotification.find_by(id: input[:notification_id])
      raise GraphQL::ExecutionError, I18n.t("Notification not found") unless notification

      closed_notifications = user.get_preference(:closed_notifications) || []
      closed_notifications << notification.id unless closed_notifications.include?(notification.id)
      user.set_preference(:closed_notifications, closed_notifications)

      {}
    end
  end
end

View on GitHub (pinned to 1c9f0bb801)