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
- Refresh the monitor list on the client before acting on a monitor and use the current user's IDs only.
- Confirm monitorID is being passed as the correct numeric value and matches a monitor in the user's own list.
- 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
- Refresh the monitor list after login and account switches.
- Pass monitorID as a number matching the list.
- Disable UI controls for monitors not in the user's list.
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
- Permission denied.
- Permission denied.
- Invalid language
- docker host not found
- domain_expiry_unsupported_monitor_type
AI-assisted analysis of louislam/uptime-kuma@6b5ea01557 (2026-08-12).
Data as JSON: /api/errors/33732f3cee79d1cc.
Report an issue: GitHub.