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

  1. Verify the event exists and is owned by the current user before calling update (fetch via Calendar.get and check uid).
  2. Refresh the client's event list to discard stale/deleted eventIds before allowing an edit.
  3. 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

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.