mastra-ai/mastra · error · HTTPException
Run id is required
Error message
Run id is required
What it means
The tool-approval/approval-result style endpoint operates on a specific run and tool call, so params.runId must be present. The handler throws HTTP 400 'Run id is required' before even checking toolCallId. The runId ties the response to the suspended run awaiting approval.
Source
Thrown at packages/server/src/server/handlers/agents.ts:2529
responseType: 'stream' as const,
streamFormat: 'sse' as const,
pathParamSchema: agentIdPathParams,
bodySchema: approveToolCallBodySchema,
responseSchema: toolCallResponseSchema,
summary: 'Approve tool call',
description: 'Approves a pending tool call and continues agent execution',
tags: ['Agents', 'Tools'],
requiresAuth: true,
handler: async ({ mastra, agentId, abortSignal, requestContext, ...params }) => {
try {
const agent = await getAgentFromSystem({
mastra,
agentId,
versionOptions: extractVersionOptions(requestContext),
});
if (!params.runId) {
throw new HTTPException(400, { message: 'Run id is required' });
}
if (!params.toolCallId) {
throw new HTTPException(400, { message: 'Tool call id is required' });
}
// UI Frameworks may send "client tools" in the body,
// but it interferes with llm providers tool handling, so we remove them
sanitizeBody(params, ['tools', 'actor']);
await validateDurableToolCallAccess({
mastra,
agent,
runId: params.runId,
toolCallId: params.toolCallId,
requestContext,
});
View on GitHub (pinned to 75dd419e61)
Solutions
- Include runId in the request body (taken from the suspended-run/watch event)
- Persist the runId alongside toolCallId when the run suspends so it survives restarts
- Check field naming matches the API schema (runId, camelCase)
Example fix
// before
await client.getAgent('a').approveToolCall({ toolCallId: 'call_1' });
// after
await client.getAgent('a').approveToolCall({ runId: 'run_abc', toolCallId: 'call_1' }); Defensive patterns
Strategy: validation
Validate before calling
function assertApprovalPayload(p: { runId?: string; toolCallId?: string }) {
if (!p.runId) throw new Error('Run id is required');
if (!p.toolCallId) throw new Error('Tool call id is required');
} Type guard
function hasApprovalIds(p: { runId?: string; toolCallId?: string }): p is { runId: string; toolCallId: string } {
return typeof p.runId === 'string' && p.runId.length > 0 && typeof p.toolCallId === 'string' && p.toolCallId.length > 0;
} Try / catch
try {
await respondToToolCall(payload);
} catch (e) {
if (e?.status === 400 && /Run id is required/.test(e.message)) {
console.error('Suspended-run state lost runId; recover from the stored suspension record');
}
throw e;
} Prevention
- Persist runId and toolCallId together whenever a run suspends on a tool call
- Take both IDs from the same suspension event, never reconstruct partially
- Type the approval request so runId is required at compile time
When it happens
Trigger: POSTing a tool call approval/continue response without runId in the request body/params.
Common situations: Client reconstructing the resume request from a webhook payload missing the run ID; runId stored under a different key in the client's suspended-run state; restarting the client process and losing the active run reference.
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
- resourceId and threadId are required when runId is not provi
- threadId is required
- Tool call id is required
- Agent ID is required
- Cannot delete the active version. Activate a different versi
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/9e6ebc321689d76e.
Report an issue: GitHub.