RocketChat/Rocket.Chat · error · Error
error-invalid-subscription
error-invalid-subscription
Error message
error-invalid-subscription
What it means
Thrown by POST subscriptions.read when Rooms.findOneById cannot find a room for the supplied rid/roomId. The endpoint marks a room as read (optionally including threads), so a valid room id is the first prerequisite. It is a plain Error, not a Meteor.Error, but the REST layer still serializes the string 'error-invalid-subscription' as the error detail.
Solutions
- Verify the id is a real room id via GET rooms.info?roomId=... before calling
- If it came from subscriptions.get, use subscription.rid (the room id), not subscription._id
- Treat this error as a signal to refresh the cached room list — the room was deleted or never existed on this server
- Double-check you are pointing at the right server (staging vs production) with matching data
Example fix
// before
await sdk.post('subscriptions.read', { rid: subscription._id }); // wrong: subscription id, not room id
// after
await sdk.post('subscriptions.read', { rid: subscription.rid }); Defensive patterns
Strategy: try-catch
Validate before calling
const { room } = await sdk.get('rooms.info', { roomId: rid }).catch(() => ({ room: null }));
if (!room) throw new Error(`room ${rid} does not exist`); Try / catch
try { await sdk.post('subscriptions.read', { rid }); } catch (e) { if (String(e?.error || e?.message).includes('error-invalid-subscription')) refreshRoomCache(); else throw e; } Prevention
- Pass subscription.rid (room id), never subscription._id
- Refresh cached room ids when a workspace is rebuilt
- Treat this error as stale-cache signal, not a transient failure
When it happens
Trigger: POST /api/v1/subscriptions.read with a rid that has a typo, a room that was deleted, a room id from a different workspace, or an id that is actually a subscription _id or message id rather than a room id.
Common situations: Sync clients caching stale room ids across workspace rebuilds; passing subscription._id (from subscriptions.get) where the room id was expected; race where the room is deleted between listing rooms and marking read.
Related errors
- invalid-room
- Emoji not found.
- error-action-not-allowed
- error-cannot-delete-team-channel
- error-challenge-not-found
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/f2d759427897f643.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/server/api/v1/subscriptions.ts:147
API.v1.post(
'subscriptions.read',
{
authRequired: true,
body: isSubscriptionsReadProps,
response: {
200: voidSuccessResponseSchema,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const { readThreads = false } = this.bodyParams;
const roomId = 'rid' in this.bodyParams ? this.bodyParams.rid : this.bodyParams.roomId;
const room = await Rooms.findOneById(roomId);
if (!room) {
throw new Error('error-invalid-subscription');
}
await readMessages(room, this.userId, readThreads);
return API.v1.success();
},
);
API.v1.post(
'subscriptions.unread',
{
authRequired: true,
body: isSubscriptionsUnreadProps,
response: {
200: voidSuccessResponseSchema,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},View on GitHub (pinned to b2c16d5842)