RocketChat/Rocket.Chat · error · Error
invalid-calendar-event
Error message
invalid-calendar-event
What it means
Thrown by the calendar event update endpoint when the authenticated user does not own the targeted event. The server calls Calendar.get(eventId) and compares event.uid against this.userId; the optional-chaining check (event?.uid) means a missing/non-existent event also trips this guard, so the error conflates 'not found' and 'not owned'. It is a plain Error (no Meteor error code), so callers cannot distinguish ownership failure from a stale ID.
Source
Thrown at apps/meteor/server/api/v1/calendar.ts:182
API.v1.post(
'calendar-events.update',
{
authRequired: true,
body: isCalendarEventUpdateProps,
response: {
200: successSchema,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const { userId } = this;
const { eventId, startTime, endTime, subject, description, meetingUrl, reminderMinutesBeforeStart, busy } = this.bodyParams;
const event = await Calendar.get(eventId);
if (event?.uid !== userId) {
throw new Error('invalid-calendar-event');
}
await Calendar.update(eventId, {
startTime: new Date(startTime),
...(endTime && { endTime: new Date(endTime) }),
subject,
description,
meetingUrl,
reminderMinutesBeforeStart,
...(typeof busy === 'boolean' && { busy }),
});
return API.v1.success();
},
);
API.v1.post(
'calendar-events.delete',View on GitHub (pinned to f9d3ec372b)
Solutions
- Verify the event exists and is owned by the current user before calling update (fetch via Calendar.get and check uid).
- Refresh the client's event list to discard stale/deleted eventIds before allowing an edit.
- If building tooling that edits others' events, add a server-side privileged path or admin permission check rather than reusing this endpoint.
Example fix
// before
const event = await Calendar.get(eventId);
if (event?.uid !== userId) {
throw new Error('invalid-calendar-event');
}
// after - distinguish missing vs. not-owned for clearer client handling
const event = await Calendar.get(eventId);
if (!event) {
throw new Meteor.Error('error-calendar-event-not-found', 'Calendar event not found');
}
if (event.uid !== userId) {
throw new Meteor.Error('error-calendar-event-not-owned', 'You do not own this calendar event');
} Defensive patterns
Strategy: validation
Validate before calling
// Before calling the calendar update endpoint, confirm ownership
async function canUpdateCalendarEvent(userId, eventId) {
const event = await Calendar.get(eventId);
return Boolean(event && event.uid === userId);
}
// usage
if (!(await canUpdateCalendarEvent(currentUserId, eventId))) {
throw new Error('Refusing update: event missing or not owned');
} Type guard
function isOwnedCalendarEvent(event, userId) {
return Boolean(event) && typeof event.uid === 'string' && event.uid === userId;
} Try / catch
try {
await api.updateCalendarEvent(eventId, patch);
} catch (e) {
if (e.message === 'invalid-calendar-event') {
// event missing or not owned - refresh list, do not blind-retry
await refreshCalendar();
return;
}
throw e;
} Prevention
- Cache eventId alongside its owner uid and re-check before edit calls.
- Discard eventIds when the user session changes.
- Distinguish 'not found' from 'not owned' in your own wrapper to avoid masking bugs.
When it happens
Trigger: POST to the calendar update endpoint with an eventId that (a) does not exist in the Calendar collection, or (b) exists but has event.uid !== the calling user's _id. Also fires if the user's session userId differs from the event owner (e.g., after account switch).
Common situations: Using a stale eventId cached client-side after the event was deleted or reassigned; passing an eventId from another user's calendar; integration tests that reuse fixtures across users.
Related errors
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/15cbfa4675b9625c.
Report an issue: GitHub.