mastra-ai/mastra · error · Error

Knowledge tools require an active threadId.

Error message

Knowledge tools require an active threadId.

What it means

The observational-memory knowledge tools derive their visibility scope from three coordinates: requestContext.organizationId, agent.resourceId, and agent.threadId. Before any knowledge tool runs, resolveScope builds the scope array [`org:...`, `resource:...`, `thread:...`] and refuses to proceed when the threadId coordinate is missing, because knowledge is always resolved within an active conversation thread. The library throws this to prevent tools from silently operating against an unbounded or ambiguous scope.

Source

Thrown at packages/memory/src/processors/observational-memory/subconscious/knowledge-tools.ts:39

    getStore(name: 'knowledge'): Promise<KnowledgeStorage | undefined>;
  };
  getKnowledgeSemanticIndex(): Promise<KnowledgeSemanticIndexCoordinator>;
};

type KnowledgeToolContext = {
  agent?: { threadId?: string; resourceId?: string };
  requestContext?: { get(key: string): unknown };
};

function resolveScope(context: KnowledgeToolContext | undefined): KnowledgeScope {
  const organizationId = context?.requestContext?.get('organizationId');
  const resourceId = resolveKnowledgeResourceId(context?.requestContext, context?.agent?.resourceId);
  const threadId = context?.agent?.threadId;
  if (typeof organizationId !== 'string' || !organizationId.trim()) {
    throw new Error('Knowledge tools require requestContext.organizationId.');
  }
  if (!resourceId) throw new Error('Knowledge tools require an active resourceId.');
  if (!threadId) throw new Error('Knowledge tools require an active threadId.');
  return [`org:${organizationId}`, `resource:${resourceId}`, `thread:${threadId}`];
}

async function getKnowledgeStore(memory: KnowledgeToolsMemory): Promise<KnowledgeStorage> {
  const store = await memory.storage.getStore('knowledge');
  if (!store) throw new Error('Knowledge tools require a configured knowledge storage domain.');
  return store;
}

function normalizeLimit(limit: number | undefined): number {
  return Math.min(Math.max(limit ?? DEFAULT_LIMIT, 1), MAX_LIMIT);
}

function serializeRecord(record: KnowledgeRecord) {
  return {
    id: record.id,
    text: record.text,
    scope: record.scope,

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Run the agent through the normal Mastra memory flow so a thread is created and context.agent.threadId is populated before tools execute.
  2. If calling tools manually, pass a context object with agent: { threadId: '<existing-thread-id>', resourceId: '<resource-id>' }.
  3. Create a thread first (via memory storage or agent.memory APIs) and use its ID.
  4. Verify requestContext also supplies organizationId and resourceId, since those are checked first and their absence masks later checks.

Example fix

// before
const tools = createKnowledgeTools(memory);
await tools.knowledge_read.execute({ id: 'node-1' }, {} as any);
// after
await tools.knowledge_read.execute({ id: 'node-1' }, {
  agent: { threadId: 'thread_123', resourceId: 'user_42' },
  requestContext: { get: (k) => (k === 'organizationId' ? 'org_1' : undefined) },
} as any);
Defensive patterns

Strategy: validation

Validate before calling

const ctx = context as { agent?: { threadId?: string; resourceId?: string }; requestContext?: { get(k: string): unknown } };
if (!ctx?.agent?.threadId) {
  throw new Error('Refusing to invoke knowledge tools: no active threadId.');
}

Type guard

function hasThreadContext(c: unknown): c is { agent: { threadId: string; resourceId: string }; requestContext: { get(k: string): unknown } } {
  const a = (c as any)?.agent;
  return typeof a?.threadId === 'string' && a.threadId.trim() !== '' && typeof a?.resourceId === 'string';
}

Try / catch

try {
  return await tools.knowledge_read.execute(args, ctx);
} catch (e) {
  if (e instanceof Error && e.message.includes('active threadId')) {
    return { error: 'no-active-thread', hint: 'Run inside a memory-backed agent thread.' };
  }
  throw e;
}

Prevention

When it happens

Trigger: Invoking any knowledge tool (knowledge_read, knowledge_search, etc.) via createKnowledgeTools when context.agent.threadId is undefined — e.g. calling the tool outside a memory-backed agent run, or in a unit test harness that stubs context without a threadId.

Common situations: Developers testing knowledge tools in isolation with a hand-rolled context object that omits threadId; running the curator/learner agent outside a normal Mastra agent loop; calling tools during startup or background jobs where no thread has been created yet.

Related errors


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