mastra-ai/mastra · error

MastraClient.deleteThread() requires exactly one of agentId

Error message

MastraClient.deleteThread() requires exactly one of agentId or networkId. The server cannot resolve which memory store owns the thread without one, and passing both is ambiguous.

What it means

MastraClient.deleteThread() enforces an exact-one-of constraint: callers must pass agentId or networkId, never both and never neither, because the server needs to know which memory store owns the thread. The throw fires when opts is falsy or when the boolean coerced values of agentId and networkId are equal (both absent or both present).

Source

Thrown at client-sdks/client-js/src/client.ts:417

    if (opts.networkId) {
      url = `/memory/network/threads/${threadId}/messages?networkId=${opts.networkId}${includeSystemRemindersQuery ? `&${includeSystemRemindersQuery}` : ''}${requestContextQueryString(opts.requestContext, includeSystemRemindersQuery ? '&' : '&')}`;
    } else if (opts.agentId) {
      url = `/memory/threads/${threadId}/messages?agentId=${opts.agentId}${includeSystemRemindersQuery ? `&${includeSystemRemindersQuery}` : ''}${requestContextQueryString(opts.requestContext, '&')}`;
    } else {
      url = `/memory/threads/${threadId}/messages${includeSystemRemindersQuery ? `?${includeSystemRemindersQuery}` : ''}${requestContextQueryString(opts.requestContext, includeSystemRemindersQuery ? '&' : '?')}`;
    }
    return this.request(url);
  }

  public deleteThread(
    threadId: string,
    opts:
      | { agentId: string; networkId?: never; requestContext?: RequestContext | Record<string, any> }
      | { networkId: string; agentId?: never; requestContext?: RequestContext | Record<string, any> },
  ): Promise<{ success: boolean; message: string }> {
    if (!opts || !!opts.agentId === !!opts.networkId) {
      throw new Error(
        'MastraClient.deleteThread() requires exactly one of agentId or networkId. ' +
          'The server cannot resolve which memory store owns the thread without one, ' +
          'and passing both is ambiguous.',
      );
    }

    const url = opts.agentId
      ? `/memory/threads/${threadId}?agentId=${opts.agentId}${requestContextQueryString(opts.requestContext, '&')}`
      : `/memory/network/threads/${threadId}?networkId=${opts.networkId}${requestContextQueryString(opts.requestContext, '&')}`;

    return this.request(url, { method: 'DELETE' });
  }

  /**
   * Saves messages to memory
   * @param params - Parameters containing messages to save and optional request context
   * @returns Promise containing the saved messages
   */

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Pass exactly one identifier: if the thread belongs to an agent use { agentId }, if it belongs to a network use { networkId }.
  2. If both values are available in your code, decide ownership explicitly before calling (e.g. prefer networkId when the thread was created by a network).
  3. Check for empty strings — they are treated as absent and trigger the neither case.

Example fix

// before
await client.deleteThread(threadId, { agentId, networkId });
// after
await client.deleteThread(threadId, networkId ? { networkId } : { agentId });
Defensive patterns

Strategy: validation

Validate before calling

function assertDeleteThreadOpts(opts: { agentId?: string; networkId?: string }) {
  const count = [opts.agentId, opts.networkId].filter(Boolean).length;
  if (count !== 1) throw new Error('deleteThread requires exactly one of agentId or networkId');
}

Type guard

function isDeleteThreadOpts(o: unknown): o is { agentId: string; networkId?: never; requestContext?: unknown } | { networkId: string; agentId?: never; requestContext?: unknown } {
  const x = o as any;
  return !!x && typeof x === 'object' && ((typeof x.agentId === 'string' && !!x.agentId && !x.networkId) || (typeof x.networkId === 'string' && !!x.networkId && !x.agentId));
}

Prevention

When it happens

Trigger: Calling client.deleteThread(threadId, {}), omitting opts entirely, or passing { agentId: 'a', networkId: 'n' }; also passing empty-string values which are falsy and count as absent.

Common situations: Migrating code from an older deleteThread(threadId, agentId?) signature and forwarding both identifiers from an agent-network context; spreading an options object that happens to contain both keys.

Related errors


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