mastra-ai/mastra · error · MastraError
AGENT_SEND_TOOL_APPROVAL_AMBIGUOUS_SUSPENDED_RUNS
AGENT_SEND_TOOL_APPROVAL_AMBIGUOUS_SUSPENDED_RUNS
Error message
Agent "${this.name}" sendToolApproval() found ${matchingRuns.length} suspended runs for thread "${threadId}". Pass a toolCallId to disambiguate, or resume a specific run with approveToolCall()/declineToolCall() and an explicit runId. What it means
Agent.sendToolApproval() collects all suspended runs for the thread, optionally filtered by toolCallId. If more than one run still matches, the target of the approval is ambiguous, so the library refuses to guess and throws. The error explicitly tells you how to disambiguate: pass a toolCallId, or use approveToolCall()/declineToolCall() with an explicit runId.
Source
Thrown at packages/core/src/agent/agent.ts:9462
// suspended-run discovery so approvals stay durable.
let suspendedRuns: AgentRun[] = [];
try {
({ runs: suspendedRuns } = await this.listSuspendedRuns({ threadId, resourceId }));
} catch (error) {
// Only swallow the expected no-storage case — storage outages and
// store-driver errors must surface instead of masquerading as
// "no suspended run exists".
if (!(error instanceof MastraError) || error.id !== 'AGENT_LIST_SUSPENDED_RUNS_NO_STORAGE') {
throw error;
}
}
const matchingRuns = options.toolCallId
? suspendedRuns.filter(run => run.toolCalls.some(toolCall => toolCall.toolCallId === options.toolCallId))
: suspendedRuns;
if (matchingRuns.length > 1) {
throw new MastraError({
id: 'AGENT_SEND_TOOL_APPROVAL_AMBIGUOUS_SUSPENDED_RUNS',
domain: ErrorDomain.AGENT,
category: ErrorCategory.USER,
text:
`Agent "${this.name}" sendToolApproval() found ${matchingRuns.length} suspended runs for thread "${threadId}". ` +
`Pass a toolCallId to disambiguate, or resume a specific run with approveToolCall()/declineToolCall() and an explicit runId.`,
details: {
threadId,
resourceId,
agentName: this.name,
runIds: matchingRuns.map(run => run.runId).join(', '),
},
});
}
runId = matchingRuns[0]?.runId;
resolvedFromStorage = runId !== undefined;
}View on GitHub (pinned to 75dd419e61)
Solutions
- Pass the toolCallId of the specific tool call you are approving in options.toolCallId.
- Switch to agent.approveToolCall() or agent.declineToolCall() with an explicit runId to target one run.
- List the suspended runs for the thread and confirm which run/tool call you intend, then retry with the explicit identifiers.
Example fix
// before
await agent.sendToolApproval({ threadId });
// after
await agent.sendToolApproval({ threadId, toolCallId: 'call_abc123' });
// or
await agent.approveToolCall({ threadId, runId: 'run_456', toolCallId: 'call_abc123' }); Defensive patterns
Strategy: validation
Validate before calling
const suspended = await getSuspendedRunsForThread(threadId); // your storage lookup
if (suspended.length > 1 && !options.toolCallId) {
throw new Error('Multiple suspended runs; supply toolCallId or explicit runId.');
} Try / catch
try {
await agent.sendToolApproval({ threadId, toolCallId });
} catch (e) {
if (String(e?.id) === 'AGENT_SEND_TOOL_APPROVAL_AMBIGUOUS_SUSPENDED_RUNS') {
// surface a picker to the user listing the suspended runs/tool calls
showDisambiguationPrompt(e);
} else throw e;
} Prevention
- Always include toolCallId in sendToolApproval calls.
- In multi-run threads, prefer approveToolCall()/declineToolCall() with an explicit runId.
- Model one pending tool approval per thread turn where possible to avoid ambiguity.
When it happens
Trigger: Calling agent.sendToolApproval({ threadId }) without toolCallId while the thread has multiple suspended runs; or passing a toolCallId that matches tool calls in more than one suspended run (duplicate toolCallIds across runs).
Common situations: Threads with several concurrently suspended agent runs (parallel tool calls or multiple resumed streams); callers storing only threadId and omitting toolCallId; tool call IDs reused after retries; bulk approval UI iterating a thread with several pending runs.
Related errors
- AGENT_SEND_TOOL_APPROVAL_NO_ACTIVE_THREAD_RUN
- AGENT_DURABLE_METHOD_NOT_AVAILABLE
- No active run to approve tool call for
- Cannot approve a tool call without a current thread
- No active run to decline tool call for
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/5b11ad84a68a3776.
Report an issue: GitHub.