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

  1. Retry the search after a short delay so the other worker finishes draining (the error is designed to be transient).
  2. For stuck 'processing' entries, ensure worker leases expire or call releaseSemanticOutbox for the dead worker's IDs.
  3. 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

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


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/8b83462787aba00b. Report an issue: GitHub.