mastra-ai/mastra · error · HTTPException

threadId is required

Error message

threadId is required

What it means

The abort endpoint needs a threadId to know which agent thread's stream to abort. After resolving effective values (including requestContext overrides), a missing threadId throws HTTP 400. resourceId is optional here — it only triggers extra ownership validation when present.

Source

Thrown at packages/server/src/server/handlers/agents.ts:2167

  summary: 'Abort active agent thread run',
  description: 'Aborts the currently active stream run for a memory thread without changing thread subscriptions',
  tags: ['Agents', 'Streaming'],
  requiresAuth: true,
  requiresPermission: 'agents:execute',
  handler: async ({ mastra, agentId, resourceId, threadId, requestContext: serverRequestContext }) => {
    try {
      const agent = await getAgentFromSystem({ mastra, agentId, requestContext: serverRequestContext });
      if (typeof (agent as { abortThreadStream?: unknown }).abortThreadStream !== 'function') {
        throw new HTTPException(501, {
          message: 'agent thread aborts are not supported by this Mastra core version',
        });
      }

      const effectiveResourceId = getEffectiveResourceId(serverRequestContext, resourceId);
      const effectiveThreadId = getEffectiveThreadId(serverRequestContext, threadId);

      if (!effectiveThreadId) {
        throw new HTTPException(400, { message: 'threadId is required' });
      }

      if (effectiveResourceId) {
        const memory = await agent.getMemory({ requestContext: serverRequestContext });
        if (memory) {
          const thread = await memory.getThreadById({ threadId: effectiveThreadId });
          await validateThreadOwnership(thread, effectiveResourceId);
        }
      }

      const aborted = await agent.abortThreadStream({ resourceId: effectiveResourceId, threadId: effectiveThreadId });
      return { aborted };
    } catch (error) {
      return handleError(error, 'error aborting agent thread');
    }
  },
});

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass threadId in the request
  2. Ensure the thread ID from stream metadata (e.g. stream.threadId) is captured and reused
  3. Check requestContext overrides if you rely on context to inject threadId

Example fix

// before
await client.getAgent('a').abortThread({ resourceId: 'u1' });
// after
await client.getAgent('a').abortThread({ resourceId: 'u1', threadId: 'thread-42' });
Defensive patterns

Strategy: validation

Validate before calling

function assertThreadId(p: { threadId?: string | null }): asserts p is { threadId: string } {
  if (!p.threadId) throw new Error('threadId is required');
}

Type guard

function hasThreadId(p: { threadId?: string | null }): p is typeof p & { threadId: string } {
  return typeof p.threadId === 'string' && p.threadId.length > 0;
}

Try / catch

try {
  await abortThread(params);
} catch (e) {
  if (e?.status === 400 && e.message === 'threadId is required') {
    console.error('Persist the threadId from the stream before aborting');
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling the thread abort route without threadId in params/body and without a requestContext override supplying it.

Common situations: Client aborting a run-level stream but passing no threadId; typo'd field name (thread_id vs threadId); thread created client-side but its ID never persisted/sent.

Understand the failure class

Background: Missing required parameter errors: what 'X is required' and 'the required X param is missing' mean, and how to fix them — this error's family across 27 libraries.

Related errors


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