RocketChat/Rocket.Chat · error · Meteor.Error
error-invalid-search-answer-sources
error-invalid-search-answer-sources
Error message
error-invalid-search-answer-sources
What it means
getSearchAnswerMessagesForUser (apps/meteor/server/api/v1/ai-search.ts) builds the source list for the intelligent-search answer endpoint (POST searchAnswer-style route gated on license + intelligentSearchEnabled + answerGenerationConfigured). It collects message IDs from the request's messages array, skipping entries without an _id, deduplicating them. If not even one usable ID remains it throws Meteor error-invalid-search-answer-sources: the answer request carries no citable sources at all.
Source
Thrown at apps/meteor/server/api/v1/ai-search.ts:190
const getSearchAnswerMessagesForUser = async (userId: string, messages: SearchAnswer['messages']) => {
const messageIds: string[] = [];
const messageIdSet = new Set<string>();
const scoreByMessageId = new Map<string, number | undefined>();
const clampScore = (score: number | undefined): number | undefined =>
typeof score === 'number' && Number.isFinite(score) ? Math.min(1, Math.max(0, score)) : undefined;
for (const { _id, score } of messages) {
if (!_id) {
continue;
}
if (!messageIdSet.has(_id)) {
messageIdSet.add(_id);
messageIds.push(_id);
}
scoreByMessageId.set(_id, clampScore(score));
}
if (!messageIds.length) {
throw new Meteor.Error('error-invalid-search-answer-sources');
}
const docs = await Messages.findVisibleByIds(messageIds, {
projection: { _id: 1, rid: 1, msg: 1, ts: 1, u: 1 },
}).toArray();
const subscribedRoomIds = await getSubscribedRoomIds(
userId,
docs.map((message) => message.rid),
);
if (docs.length !== messageIds.length || docs.some((message) => !subscribedRoomIds.has(message.rid))) {
throw new Meteor.Error('error-invalid-search-answer-sources');
}
const normalizedDocs = await normalizeMessagesForUser(docs, userId);
const docsById = new Map(normalizedDocs.map((message) => [message._id, message]));
const rooms = await getRoomMap(normalizedDocs.map((message) => message.rid));
const answerMessages = [];View on GitHub (pinned to b2c16d5842)
Solutions
- Pass at least one entry with a non-empty _id: { "messages": [{ "_id": "aobEdbYhXfu5hkeqG", "score": 0.9 }] }
- Take source IDs from the ai-search results endpoint rather than fabricating them
- If the search step legitimately found nothing, skip the answer request — there is nothing to cite
Example fix
// before
POST /api/v1/ai-search/answer { "messages": [] } // -> error-invalid-search-answer-sources
// after
POST /api/v1/ai-search/answer { "messages": [{ "_id": "aobEdbYhXfu5hkeqG", "score": 0.9 }] } Defensive patterns
Strategy: validation
Validate before calling
function assertAnswerSources(messages: Array<{ _id?: string; score?: number }>) {
const ids = messages.filter((m) => typeof m._id === 'string' && m._id.trim() !== '');
if (!ids.length) throw new Error('answer request needs >=1 message with a non-empty _id');
return ids;
} Type guard
const isSearchAnswerSource = (v: unknown): v is { _id: string; score?: number } =>
typeof v === 'object' && v !== null && typeof (v as any)._id === 'string' && (v as any)._id.length > 0; Try / catch
try {
const { data } = await client.post('/api/v1/ai-search/answer', { messages });
} catch (e: any) {
if (e?.response?.data?.errorType === 'error-invalid-search-answer-sources' && !messages.some((m) => m._id)) {
throw new ValidationError('no citable sources — run the search step first');
}
throw e;
} Prevention
- Skip the answer call when the preceding search returned zero hits
- Name the field _id exactly — id/messageId variants are dropped silently
- Verify intelligent search + answer generation are configured before building answer UX
When it happens
Trigger: POST to the AI search answer endpoint with messages: [] or with entries that all lack _id (e.g. [{score:0.8}]). The endpoint status checks pass, then this validation fails before any DB access.
Common situations: Client forwarding an empty sources array because the upstream search step returned no hits; schema drift where the field is named id/messageId instead of _id; testing the endpoint with placeholder payloads.
Related errors
- error-users-params-not-provided
- error-invalid-sort
- error-invalid-fields
- error-invalid-query
- Type not supported
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/5154609733d17b4d.
Report an issue: GitHub.