mastra-ai/mastra · error

No thread found with id ${threadId}

Error message

No thread found with id ${threadId}

What it means

recall() validates that the given threadId exists when semantic recall is thread-scoped. If getThreadById returns no thread and resourceScope is not enabled, the error is thrown. It is a lookup failure: the thread id does not exist in storage.

Source

Thrown at packages/memory/src/index.ts:578

    return store;
  }

  async listMessagesByResourceId(args: StorageListMessagesByResourceIdInput): Promise<StorageListMessagesOutput> {
    const memoryStore = await this.getMemoryStore();
    return memoryStore.listMessagesByResourceId(args);
  }

  protected async validateThreadIsOwnedByResource(threadId: string, resourceId: string, config: MemoryConfigInternal) {
    const resourceScope =
      (typeof config?.semanticRecall === 'object' && config?.semanticRecall?.scope !== `thread`) ||
      config.semanticRecall === true;

    const thread = await this.getThreadById({ threadId });

    // For resource-scoped semantic recall, we don't need to validate that the specific thread exists
    // because we're searching across all threads for the resource
    if (!thread && !resourceScope) {
      throw new Error(`No thread found with id ${threadId}`);
    }

    // If thread exists, validate it belongs to the correct resource
    if (thread && thread.resourceId !== resourceId) {
      throw new Error(
        `Thread with id ${threadId} is for resource with id ${thread.resourceId} but resource ${resourceId} was queried.`,
      );
    }
  }

  private createMemorySpan(
    operationType: MemoryOperationAttributes['operationType'],
    observabilityContext?: Partial<ObservabilityContext>,
    input?: any,
    attributes?: Partial<MemoryOperationAttributes>,
  ) {
    const currentSpan = observabilityContext?.tracingContext?.currentSpan;
    if (!currentSpan) return undefined;

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Check that the thread id exists via memory.getThreadById({ threadId }) before recall
  2. Create the thread first (memory.createThread) or recall only for existing threads
  3. Enable resource-scoped recall (semanticRecall: { scope: 'resource' }) so recall searches across the resource's threads instead of requiring the specific thread
  4. Fix stale ids in application state (persist and reuse the id returned from createThread)

Example fix

// before
await memory.recall({ threadId: maybeThreadId, resourceId });
// after
const thread = await memory.getThreadById({ threadId: maybeThreadId });
if (!thread) throw new Error(`Thread ${maybeThreadId} does not exist`);
await memory.recall({ threadId: maybeThreadId, resourceId });
Defensive patterns

Strategy: try-catch

Validate before calling

const thread = await memory.getThreadById({ threadId });
if (!thread && !resourceScope) throw new Error(`Cannot recall: thread ${threadId} not found`);

Try / catch

try {
  await memory.recall({ threadId, resourceId });
} catch (e) {
  if (e instanceof Error && e.message.includes('No thread found with id')) {
    // recreate thread or skip recall
  } else throw e;
}

Prevention

When it happens

Trigger: Calling memory.recall({ threadId, resourceId }) with a threadId that was never created or was deleted, while semanticRecall is scoped to 'thread' (or semanticRecall is false/undefined so resourceScope is false).

Common situations: Replaying an old conversation after the DB was reset; typos or stale thread ids passed from application state; threads deleted by retention/cleanup jobs.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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