RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-subscription
error-invalid-subscription
Error message
Invalid subscription
What it means
Thrown by POST rooms.saveDraft when Subscriptions.updateDraftByRoomIdAndUserId matched zero rows — i.e. the calling user has no subscription (membership) for that room. Drafts are stored on the membership record, so no membership means no draft can be saved.
Source
Thrown at apps/meteor/server/api/v1/rooms.ts:463
{
authRequired: true,
body: saveDraftBodySchema,
response: {
200: saveDraftResponseSchema,
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const { rid, draft, tmid } = this.bodyParams;
if (draft.length > (settings.get<number>('Message_MaxAllowedSize') ?? 0)) {
return API.v1.failure('error-message-size-exceeded');
}
const subscription = await Subscriptions.updateDraftByRoomIdAndUserId(rid, this.userId, draft || undefined, tmid);
if (!subscription) {
throw new Meteor.Error('error-invalid-subscription', 'Invalid subscription');
}
void notifyOnSubscriptionChanged(subscription);
return API.v1.success();
},
);
API.v1.post(
'rooms.cleanHistory',
{
authRequired: true,
body: isRoomsCleanHistoryProps,
response: {
200: ajv.compile<{ _id: string; count: number }>({
type: 'object',
properties: {
_id: { type: 'string' },View on GitHub (pinned to f9d3ec372b)
Solutions
- Verify membership before saving the draft (subscriptions.getOne?roomId=).
- If the user has left, suppress draft-save calls from the client for that room.
- For bots, ensure the bot user is added to the room before invoking saveDraft.
Example fix
// before
await rest.post('/api/v1/rooms.saveDraft', { rid, draft });
// after
const sub = await rest.get(`/api/v1/subscriptions.getOne?roomId=${rid}`);
if (sub.subscription) {
await rest.post('/api/v1/rooms.saveDraft', { rid, draft });
} Defensive patterns
Strategy: validation
Validate before calling
const { subscription } = await rest.get(`/api/v1/subscriptions.getOne?roomId=${rid}`);
if (!subscription) {
// user isn't a member — skip draft save silently
return;
}
await rest.post('/api/v1/rooms.saveDraft', { rid, draft, tmid }); Type guard
function isRoomMember(sub: unknown): boolean {
return !!sub && typeof (sub as any).rid === 'string';
} Try / catch
try {
await rest.post('/api/v1/rooms.saveDraft', { rid, draft, tmid });
} catch (e) {
if (isMeteorError(e, 'error-invalid-subscription')) {
// leave the draft local; user is not a member
} else throw e;
} Prevention
- Drop draft-save timers for rooms the user has left.
- For bots, ensure room membership before calling.
- Treat this error as non-fatal — keep the draft client-side.
When it happens
Trigger: POST /api/v1/rooms.saveDraft with { rid, draft, tmid } for a room the authenticated user is not a member of, has left, or was removed from.
Common situations: User left the channel but the client still has it open; bots calling on behalf of users who aren't members; dry-run/test accounts; race after a kick/ban.
Related errors
- User not subscribed to room
- error-roomId-param-invalid
- error-invalid-subscription
- Room not found
- not-subscribed-room
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/007601187fe2624c.
Report an issue: GitHub.