mastra-ai/mastra · warning · StaleKnowledgeSemanticIndexError
Knowledge semantic index remained stale after ${MAX_DRAIN_BA
Error message
Knowledge semantic index remained stale after ${MAX_DRAIN_BATCHES} processing batches. What it means
`#drain` (semantic-index.ts:151) caps how many outbox batches it processes per search (`MAX_DRAIN_BATCHES`). If the outbox still has visible work after that many batches, it throws `StaleKnowledgeSemanticIndexError` rather than blocking the request indefinitely — the backlog is too large to drain within one search call.
Source
Thrown at packages/memory/src/processors/observational-memory/subconscious/semantic-index.ts:151
for (let index = 0; index < entries.length; index++) {
const entry = entries[index]!;
try {
await this.#apply(entry);
await this.#knowledge.completeSemanticOutbox({ ids: [entry.id], workerId: this.#workerId });
processed++;
} catch (error) {
await this.#knowledge.releaseSemanticOutbox({
ids: entries.slice(index).map(pendingEntry => pendingEntry.id),
workerId: this.#workerId,
});
throw new StaleKnowledgeSemanticIndexError(
`Knowledge semantic index is stale because operation ${entry.id} could not be applied.`,
{ cause: error },
);
}
}
}
throw new StaleKnowledgeSemanticIndexError(
`Knowledge semantic index remained stale after ${MAX_DRAIN_BATCHES} processing batches.`,
);
}
async #apply(entry: KnowledgeSemanticOutboxEntry): Promise<void> {
if (entry.operation === 'delete') {
await this.#deleteDocument(entry.documentId);
return;
}
const document = await this.#loadDocument(entry);
if (!document) {
await this.#deleteDocument(entry.documentId);
return;
}
const result = await this.#embedder.doEmbed({
values: [document.text],
...(this.#embedderOptions ?? {}),View on GitHub (pinned to 75dd419e61)
Solutions
- Run the indexer/drain as a background job first, then search once the outbox is empty.
- Increase throughput (batch embedding, faster embedder/vector store) or tune MAX_DRAIN_BATCHES if appropriate.
- Check for stuck 'processing' entries from crashed workers and release them so drains make progress.
- Retry with backoff — each attempt drains more of the backlog.
Example fix
// before await bulkImport(docs); await remind(context); // StaleKnowledgeSemanticIndexError: backlog too big // after await bulkImport(docs); await backgroundDrainWorker.runToCompletion(); // drain fully before searching await remind(context);
Defensive patterns
Strategy: retry
Validate before calling
const backlog = await store.listSemanticOutbox({ status: 'pending', scope, limit: 1000 });
if (backlog.length > 100) console.warn(`semantic outbox backlog (${backlog.length}) may exceed drain budget`); Try / catch
try {
return await remind(context);
} catch (e) {
if (e instanceof StaleKnowledgeSemanticIndexError && e.message.includes('remained stale after')) {
await backgroundDrain(); // drain off the request path, then retry once
return remind(context);
}
throw e;
} Prevention
- Drain the outbox in a scheduled background worker instead of relying on search-time draining.
- Throttle bulk knowledge imports; batch embed for throughput.
- Alert on growing pending-outbox depth per scope.
When it happens
Trigger: A large backlog of pending semantic outbox operations (bulk import, mass deletes, many threads' knowledge) exceeding MAX_DRAIN_BATCHES, or a slow embedder/vector store making each batch small so the queue never empties within the budget.
Common situations: Bulk-loading knowledge then immediately searching; high-latency embedding providers; many concurrent writers generating outbox entries faster than one drain can process.
Related errors
- Knowledge semantic index is stale: a visible operation is pe
- Knowledge semantic index is stale because operation ${entry.
- Knowledge semantic index ${indexName} is unavailable. Captur
- Embedder returned no vector for ${entry.documentId}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/4e95d749a63e24b3.
Report an issue: GitHub.