louislam/uptime-kuma · error · Error

notification not found

Error message

notification not found

What it means

Thrown by Notification.save during an update (notificationID provided) when no notification row matches both the given id AND the user_id. The AND user_id clause enforces ownership: a missing row means either the id does not exist or it belongs to a different user.

Source

Thrown at server/notification.js:272

            throw new Error("Notification type is not supported");
        }
    }

    /**
     * Save a notification
     * @param {object} notification Notification to save
     * @param {?number} notificationID ID of notification to update
     * @param {number} userID ID of user who adds notification
     * @returns {Promise<Bean>} Notification that was saved
     */
    static async save(notification, notificationID, userID) {
        let bean;

        if (notificationID) {
            bean = await R.findOne("notification", " id = ? AND user_id = ? ", [notificationID, userID]);

            if (!bean) {
                throw new Error("notification not found");
            }
        } else {
            bean = R.dispense("notification");
        }

        // applyExisting is one time only, don't save it to database.
        const applyExisting = notification.applyExisting || false;
        notification.applyExisting = false;

        bean.name = notification.name;
        bean.user_id = userID;
        bean.config = JSON.stringify(notification);
        bean.is_default = notification.isDefault || false;
        await R.store(bean);

        if (applyExisting) {
            await applyNotificationEveryMonitor(bean.id, userID);
        }

View on GitHub (pinned to 6b5ea01557)

Solutions

  1. Refresh the notifications list in the UI to discard stale ids and retry the edit.
  2. Confirm the authenticated user actually owns the notification (check user_id in the DB row).
  3. If the notification was deleted intentionally, create a new one instead of updating the old id.
  4. Inspect server logs to confirm the (notificationID, userID) pair being passed.
Defensive patterns

Strategy: validation

Validate before calling

// Verify ownership before attempting an update
async function notificationExistsForUser(notificationID, userID) {
    const bean = await R.findOne("notification", " id = ? AND user_id = ? ", [notificationID, userID]);
    return bean != null;
}
if (notificationID && !(await notificationExistsForUser(notificationID, userID))) {
    throw new Error("notification not found");
}

Type guard

/** True when a bean was found for the (id, user) pair. */
function isOwnedNotification(bean) { return bean != null; }

Try / catch

try {
    const bean = await R.findOne("notification", " id = ? AND user_id = ? ", [notificationID, userID]);
    if (!bean) throw new Error("notification not found");
    // ...proceed with update
} catch (err) { throw err; }

Prevention

When it happens

Trigger: Editing a notification whose id was already deleted, a stale id held in the browser after another session deleted it, or a user_id mismatch (wrong user editing another's notification, possibly via a tampered request).

Common situations: Two browser tabs open: one deletes the notification while the other tries to save; client-side id caching after deletion; or privilege escalation attempt via crafted notificationID.

Related errors


AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12). Data as JSON: /api/errors/987c289a63031724. Report an issue: GitHub.