louislam/uptime-kuma · error · Error

You do not own this monitor.

Error message

You do not own this monitor.

What it means

Thrown by checkOwner(userID, monitorID) when a SQL lookup for a monitor row matching both monitorID and userID returns no row. It is the server-side ownership gate ensuring a user can only act on monitors belonging to them. The function is documented as rejecting when 'the specified user does not own the monitor.'

Solutions

  1. Refresh the monitor list on the client before acting on a monitor and use the current user's IDs only.
  2. Confirm monitorID is being passed as the correct numeric value and matches a monitor in the user's own list.
  3. If the monitor was shared/deleted, surface a not-found/permission UI instead of retrying the same call.
Defensive patterns

Strategy: validation

Validate before calling

// Verify ownership client-side before calling owned-monitor APIs
const owned = monitorList.some(m => m.id === monitorID);
if (!owned) {
  throw new Error(`monitor ${monitorID} not owned by current user`);
}

Type guard

function isOwnedMonitor(monitorID, monitorList) {
  return Array.isArray(monitorList)
    && monitorList.some(m => Number(m.id) === Number(monitorID));
}

Try / catch

try {
  await emitAsync("someMonitorAction", monitorID);
} catch (e) {
  if (/do not own this monitor/i.test(e.message)) refreshMonitorList();
  else throw e;
}

Prevention

When it happens

Trigger: Any handler that calls checkOwner after checkLogin, passing a monitorID that either does not exist or exists under a different user_id than socket.userID. The query SELECT id FROM monitor WHERE id = ? AND user_id = ? yields no row.

Common situations: Stale client state referencing a monitor that was deleted; cross-tenant access attempt; monitorID sent as a string/non-numeric so the parametrized query finds nothing; account switch where the cached monitor list belongs to another user.

Related errors


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

Appendix: source

Thrown at server/server.js:1817

            relation.monitor_id = monitorID;
            relation.notification_id = notificationID;
            await R.store(relation);
        }
    }
}

/**
 * Check if a given user owns a specific monitor
 * @param {number} userID ID of user to check
 * @param {number} monitorID ID of monitor to check
 * @returns {Promise<void>}
 * @throws {Error} The specified user does not own the monitor
 */
async function checkOwner(userID, monitorID) {
    let row = await R.getRow("SELECT id FROM monitor WHERE id = ? AND user_id = ? ", [monitorID, userID]);

    if (!row) {
        throw new Error("You do not own this monitor.");
    }
}

/**
 * Function called after user login
 * This function is used to send the heartbeat list of a monitor.
 * @param {Socket} socket Socket.io instance
 * @param {object} user User object
 * @returns {Promise<void>}
 */
async function afterLogin(socket, user) {
    socket.userID = user.id;
    socket.join(user.id);

    let monitorList = await server.sendMonitorList(socket);
    await Promise.allSettled([
        sendInfo(socket),
        server.sendMaintenanceList(socket),

View on GitHub (pinned to 6b5ea01557)