mastra-ai/mastra · warning · StaleKnowledgeSemanticIndexError
Knowledge semantic index is stale: a visible operation is pe
Error message
Knowledge semantic index is stale: a visible operation is pending or being processed by another worker.
What it means
`#drain` (semantic-index.ts:126) processes the semantic outbox so the index is current before searching. When its own batch is empty but the store still reports pending or processing outbox operations for the visible scope, another worker owns those writes; the index may not yet reflect recent knowledge, so it throws `StaleKnowledgeSemanticIndexError` rather than serving possibly-stale results.
Source
Thrown at packages/memory/src/processors/observational-memory/subconscious/semantic-index.ts:126
.sort((left, right) => right.score - left.score || left.id.localeCompare(right.id))
.slice(0, limit);
}
async #drain(scope?: KnowledgeScope): Promise<number> {
let processed = 0;
for (let batch = 0; batch < MAX_DRAIN_BATCHES; batch++) {
const entries = await this.#knowledge.claimSemanticOutbox({
workerId: this.#workerId,
limit: this.#batchSize,
scope,
});
if (entries.length === 0) {
const [pending, processing] = await Promise.all([
this.#knowledge.listSemanticOutbox({ status: 'pending', scope, limit: 1 }),
this.#knowledge.listSemanticOutbox({ status: 'processing', scope, limit: 1 }),
]);
if (pending.length > 0 || processing.length > 0) {
throw new StaleKnowledgeSemanticIndexError(
'Knowledge semantic index is stale: a visible operation is pending or being processed by another worker.',
);
}
return processed;
}
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(View on GitHub (pinned to 75dd419e61)
Solutions
- Retry the search after a short delay so the other worker finishes draining (the error is designed to be transient).
- For stuck 'processing' entries, ensure worker leases expire or call releaseSemanticOutbox for the dead worker's IDs.
- Reduce concurrency on the same scope, or route remind traffic to a single indexer per scope.
Example fix
// before
await remind(context); // throws while another worker drains
// after
try {
await remind(context);
} catch (e) {
if (e instanceof StaleKnowledgeSemanticIndexError) {
await delay(1000);
return remind(context); // retry
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
const [pending, processing] = await Promise.all([
store.listSemanticOutbox({ status: 'pending', scope, limit: 1 }),
store.listSemanticOutbox({ status: 'processing', scope, limit: 1 }),
]);
const busy = pending.length > 0 || processing.length > 0; Type guard
function isOutboxIdle(entries) {
return entries.length === 0;
} Try / catch
try {
return await remind(context);
} catch (e) {
if (e instanceof StaleKnowledgeSemanticIndexError && e.message.includes('pending or being processed')) {
await new Promise((r) => setTimeout(r, 1000));
return remind(context); // transient: another worker is draining
}
throw e;
} Prevention
- Wrap remind/search in bounded retry with backoff.
- Monitor for outbox entries stuck in 'processing' and release leases of dead workers.
- Limit concurrent writers per scope or use a single indexer worker.
When it happens
Trigger: Concurrent workers: this instance drains zero entries while `listSemanticOutbox({ status: 'pending' | 'processing', scope })` returns at least one entry — another worker is mid-write, or a crashed worker left operations stuck in 'processing' without releasing them.
Common situations: Multiple app instances writing knowledge simultaneously; a worker crashed mid-batch leaving operations locked in 'processing'; long-running batch jobs holding the outbox while a request triggers remind.
Related errors
- Knowledge semantic index is stale because operation ${entry.
- Knowledge semantic index remained stale after ${MAX_DRAIN_BA
- MastraFactory.prepare() called twice
- Factory kickoff lease was lost before completion.
- ${file} is in use by another process — is another Mastra Cod
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/8b83462787aba00b.
Report an issue: GitHub.