mastra-ai/mastra · error
Cannot decline a tool call without a current thread
Error message
Cannot decline a tool call without a current thread
What it means
Thrown when declining a tool call while the session has no current thread. The decline decision is persisted via `agent.sendToolApproval`, which requires a `threadId`; when `this.thread.getId()` returns undefined the library cannot record the decline and throws.
Source
Thrown at packages/core/src/agent-controller/session.ts:3797
toolCallId,
requestContext: requestContextInput,
declineContext,
}: {
toolCallId?: string;
requestContext?: RequestContext;
declineContext?: { reason?: string; message?: string };
}): Promise<void> {
const runId = this.run.getRunId();
if (!runId) {
throw new Error('No active run to decline tool call for');
}
const agent = this.machinery.getAgent();
const requestContext = await this.machinery.buildRequestContext(requestContextInput);
const isYolo = (this.state.get() as Record<string, unknown>).yolo === true;
const threadId = this.thread.getId();
if (!threadId) {
throw new Error('Cannot decline a tool call without a current thread');
}
const resourceId = this.identity.getResourceId();
await agent.sendToolApproval({
threadId,
resourceId,
runId,
toolCallId,
approved: false,
declineContext,
requireToolApproval: !isYolo,
memory: { thread: threadId, resource: resourceId },
abortSignal: this.run.ensureAbortController().signal,
requestContext,
toolsets: await this.machinery.buildToolsets(requestContext),
});
}
private createSubscribedResumeBoundaryWaiter(toolCallId?: string): { promise: Promise<void>; cancel: () => void } {View on GitHub (pinned to 75dd419e61)
Solutions
- Establish a current thread on the session (start the run or explicitly select/create the thread) before declining.
- Check that cleanup logic isn't clearing the thread while a tool approval is pending.
- Route the decline through the same session/thread that issued the tool call request.
Example fix
// before
await session.declineToolCall({ toolCallId });
// after
const threadId = session.getCurrentThreadId?.();
if (!threadId) throw new Error('Select a thread before declining tool calls');
await session.declineToolCall({ toolCallId }); Defensive patterns
Strategy: validation
Validate before calling
// before declining
const threadId = session.getCurrentThreadId?.();
if (!threadId) {
throw new Error('A current thread is required to decline tool calls');
} Type guard
function hasThreadForDecline(session: { getCurrentThreadId?: () => string | undefined }): session is { getCurrentThreadId: () => string } {
return typeof session.getCurrentThreadId === 'function' && typeof session.getCurrentThreadId() === 'string';
} Try / catch
try {
await session.declineToolCall({ toolCallId });
} catch (err) {
if (err instanceof Error && err.message.includes('without a current thread')) {
await session.selectThread(originalThreadId);
await session.declineToolCall({ toolCallId });
} else throw err;
} Prevention
- Verify thread selection before enabling any tool-approval actions (approve or decline).
- Avoid resetting threads mid-run; defer cleanup until pending decisions resolve.
- Route decisions through the session that owns the originating thread.
When it happens
Trigger: Calling the decline-tool-call method on a session whose thread ID is unset — no thread created/selected, or thread state cleared before the decline call.
Common situations: Declining a tool call on a brand-new session with no conversation history; thread reset/cleanup racing with the decline; routing declines to a session instance different from the one owning the thread.
Related errors
- Cannot approve a tool call without a current thread
- AGENT_SEND_TOOL_APPROVAL_AMBIGUOUS_SUSPENDED_RUNS
- AGENT_SEND_TOOL_APPROVAL_NO_ACTIVE_THREAD_RUN
- Received input message with wrong threadId. Input ${message.
- No active run to approve tool call for
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/ed747167a1e12fe2.
Report an issue: GitHub.