RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-message
error-invalid-message
Error message
Invalid Message
What it means
Thrown by chat.readThread when Messages.findOneById(tmid, { projection: { rid: 1 } }) returns no document or one without an rid - i.e., the supplied thread parent message (tmid) does not exist. Meteor.Error code 'error-invalid-message'. This runs only after the Threads_enabled check passes.
Source
Thrown at apps/meteor/server/api/v1/chat.ts:289
type: 'boolean',
enum: [true],
},
},
required: ['success'],
additionalProperties: false,
}),
},
},
async function action() {
if (!settings.get<boolean>('Threads_enabled')) {
throw new Meteor.Error('error-not-allowed', 'Threads Disabled');
}
const { tmid } = this.bodyParams;
const thread = await Messages.findOneById(tmid, { projection: { rid: 1 } });
if (!thread?.rid) {
throw new Meteor.Error('error-invalid-message', 'Invalid Message');
}
const [user, room] = await Promise.all([
Users.findOneById(this.userId),
Rooms.findOneById(thread.rid, { projection: { ...roomAccessAttributes, t: 1, _id: 1 } }),
]);
if (!room) {
throw new Meteor.Error('error-room-does-not-exist', 'This room does not exist');
}
if (!user || !(await canAccessRoomAsync(room, user))) {
throw new Meteor.Error('error-not-allowed', 'Not Allowed');
}
await callbacks.run('beforeReadMessages', room._id, user._id);
await readThread({ user, room, tmid });
View on GitHub (pinned to f9d3ec372b)
Solutions
- Confirm tmid refers to the thread-root message (the parent), not a reply within the thread.
- Validate that the thread root still exists before marking read.
- Handle error-invalid-message by refreshing the thread list.
Example fix
// before
await fetch('/api/v1/chat.readThread', { method: 'POST', body: JSON.stringify({ tmid }) });
// after
const root = await fetchMessage(tmid);
if (!root || !root.rid) {
refreshThreadList();
return;
}
await fetch('/api/v1/chat.readThread', { method: 'POST', body: JSON.stringify({ tmid }) }); Defensive patterns
Strategy: validation
Validate before calling
async function threadRootExists(tmid) {
const msg = await Messages.findOneById(tmid, { projection: { rid: 1 } });
return Boolean(msg && msg.rid);
} Type guard
function isValidThreadRoot(msg) {
return Boolean(msg) && typeof msg.rid === 'string' && msg.rid.length > 0;
} Try / catch
try {
await api.readThread({ tmid });
} catch (e) {
if (e.error === 'error-invalid-message') {
refreshThreadList(); // tmid stale or wrong
return;
}
throw e;
} Prevention
- Pass the thread-root message id as tmid, not a reply id.
- Validate the thread root still exists before marking read.
- Refresh thread lists when tmid lookups fail.
When it happens
Trigger: POST chat.readThread with a tmid that is not a real message id, or that is a message with no rid (malformed/deleted).
Common situations: Stale tmid from a thread whose parent message was deleted; tmid typo; using a reply message id as tmid instead of the thread root.
Related errors
- error-updatedSince-param-invalid
- error-not-allowed
- error-room-does-not-exist
- The required "mid" body param is missing.
- error-emoji-param-not-provided
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/0c21c63e5b34771a.
Report an issue: GitHub.