mastra-ai/mastra · error

Cannot resume a suspended tool without a current thread

Error message

Cannot resume a suspended tool without a current thread

What it means

Thrown while resuming a suspended tool when the session has no current thread. After the suspension is validated and removed from the registry, the resume flow needs a thread to re-subscribe to and continue the run within (`this.thread.ensureSubscription(threadId)`); a missing thread ID means the resumed run has no conversation context, so the library throws.

Source

Thrown at packages/core/src/agent-controller/session.ts:3872

  }): Promise<void> {
    const suspension = this.suspensions.get({ toolCallId });
    if (!suspension) {
      throw new Error('No active suspension to resume');
    }

    const agent = this.machinery.getAgent();

    // Remove before resuming so a re-suspend during the resumed run can
    // re-register the same toolCallId without being clobbered by this cleanup.
    // Drop the matching display-state entry too so the UI stops rendering the
    // resolved prompt while any other parked suspensions stay visible.
    this.suspensions.delete({ toolCallId });
    this.displayState.deletePendingSuspension(toolCallId);

    const requestContext = await this.machinery.buildRequestContext(requestContextInput);
    const threadId = this.thread.getId();
    if (!threadId) {
      throw new Error('Cannot resume a suspended tool without a current thread');
    }

    await this.thread.ensureSubscription(threadId);
    const resumedSubscriptionBoundary = this.createSubscribedResumeBoundaryWaiter(
      suspension.toolName === 'submit_plan' ? toolCallId : undefined,
    );

    try {
      const resourceId = this.identity.getResourceId();
      const sharedOptions = this.machinery.buildSharedRunOptions();
      // Interactive builtins suspend to collect user input, not for approval.
      // The resume data is the user's answer (a bare string), which the approval
      // re-check would reject because it cannot carry an `{ approved }` field.
      // Exempt these tools so the answer reaches the model as-is.
      const isInteractive = suspension.toolName === 'ask_user' || suspension.toolName === 'request_access';
      if (isInteractive) {
        sharedOptions.requireToolApproval = false;
      }

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Restore/select the original thread on the session before resuming the suspended tool.
  2. Ensure the resume goes through the same session (or one bound to the same thread) that received the suspension.
  3. Check for code paths that clear the current thread while suspensions are still pending.

Example fix

// before
await session.resumeSuspendedTool({ toolCallId, resumeData });

// after
if (!session.getCurrentThreadId?.()) {
  await session.selectThread(originalThreadId);
}
await session.resumeSuspendedTool({ toolCallId, resumeData });
Defensive patterns

Strategy: validation

Validate before calling

// before resuming
const threadId = session.getCurrentThreadId?.();
if (!threadId) {
  await session.selectThread(originalThreadId); // restore conversation context first
}

Type guard

function canResume(session: { getCurrentThreadId?: () => string | undefined }): boolean {
  return typeof session.getCurrentThreadId === 'function' && typeof session.getCurrentThreadId() === 'string';
}

Try / catch

try {
  await session.resumeSuspendedTool({ toolCallId, resumeData });
} catch (err) {
  if (err instanceof Error && err.message.includes('without a current thread')) {
    await session.selectThread(originalThreadId);
    await session.resumeSuspendedTool({ toolCallId, resumeData });
  } else throw err;
}

Prevention

When it happens

Trigger: Calling resume on a valid suspension but on a session where `this.thread.getId()` is undefined — thread never set, thread cleared, or the suspension was handled by a different session instance than the one owning the conversation.

Common situations: Recreating a session (e.g., after a page reload) and resuming without restoring the thread; clearing thread state during resume; multi-session apps routing the resume to the wrong instance.

Related errors


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