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.'

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)

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.