{"record":{"id":"f2d759427897f643","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-subscription-f2d759","errorCode":"error-invalid-subscription","errorMessage":"error-invalid-subscription","messagePattern":"error-invalid-subscription","errorType":"exception","errorClass":"Error","httpStatus":400,"severity":"error","filePath":"apps/meteor/server/api/v1/subscriptions.ts","lineNumber":147,"sourceCode":"\nAPI.v1.post(\n\t'subscriptions.read',\n\t{\n\t\tauthRequired: true,\n\t\tbody: isSubscriptionsReadProps,\n\t\tresponse: {\n\t\t\t200: voidSuccessResponseSchema,\n\t\t\t400: validateBadRequestErrorResponse,\n\t\t\t401: validateUnauthorizedErrorResponse,\n\t\t},\n\t},\n\tasync function action() {\n\t\tconst { readThreads = false } = this.bodyParams;\n\t\tconst roomId = 'rid' in this.bodyParams ? this.bodyParams.rid : this.bodyParams.roomId;\n\n\t\tconst room = await Rooms.findOneById(roomId);\n\t\tif (!room) {\n\t\t\tthrow new Error('error-invalid-subscription');\n\t\t}\n\n\t\tawait readMessages(room, this.userId, readThreads);\n\n\t\treturn API.v1.success();\n\t},\n);\n\nAPI.v1.post(\n\t'subscriptions.unread',\n\t{\n\t\tauthRequired: true,\n\t\tbody: isSubscriptionsUnreadProps,\n\t\tresponse: {\n\t\t\t200: voidSuccessResponseSchema,\n\t\t\t400: validateBadRequestErrorResponse,\n\t\t\t401: validateUnauthorizedErrorResponse,\n\t\t},","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/api/v1/subscriptions.ts#L129-L165","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait sdk.post('subscriptions.read', { rid: subscription._id }); // wrong: subscription id, not room id\n// after\nawait sdk.post('subscriptions.read', { rid: subscription.rid });","handlingStrategy":"try-catch","validationCode":"const { room } = await sdk.get('rooms.info', { roomId: rid }).catch(() => ({ room: null }));\nif (!room) throw new Error(`room ${rid} does not exist`);","typeGuard":null,"tryCatchPattern":"try { await sdk.post('subscriptions.read', { rid }); } catch (e) { if (String(e?.error || e?.message).includes('error-invalid-subscription')) refreshRoomCache(); else throw e; }","preventionTips":["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"],"tags":["rest-api","rooms","subscriptions","not-found"],"backgroundTag":"room-not-found","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}