{"record":{"id":"0d58a9dec0c0acfd","repo":"mastra-ai/mastra","slug":"tool-call-id-is-required","errorCode":null,"errorMessage":"Tool call id is required","messagePattern":"Tool call id is required","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"packages/server/src/server/handlers/agents.ts","lineNumber":2533,"sourceCode":"  responseSchema: toolCallResponseSchema,\n  summary: 'Approve tool call',\n  description: 'Approves a pending tool call and continues agent execution',\n  tags: ['Agents', 'Tools'],\n  requiresAuth: true,\n  handler: async ({ mastra, agentId, abortSignal, requestContext, ...params }) => {\n    try {\n      const agent = await getAgentFromSystem({\n        mastra,\n        agentId,\n        versionOptions: extractVersionOptions(requestContext),\n      });\n\n      if (!params.runId) {\n        throw new HTTPException(400, { message: 'Run id is required' });\n      }\n\n      if (!params.toolCallId) {\n        throw new HTTPException(400, { message: 'Tool call id is required' });\n      }\n\n      // UI Frameworks may send \"client tools\" in the body,\n      // but it interferes with llm providers tool handling, so we remove them\n      sanitizeBody(params, ['tools', 'actor']);\n\n      await validateDurableToolCallAccess({\n        mastra,\n        agent,\n        runId: params.runId,\n        toolCallId: params.toolCallId,\n        requestContext,\n      });\n\n      const streamResult = await agent.approveToolCall({\n        ...params,\n        requestContext,\n        abortSignal,","sourceCodeStart":2515,"sourceCodeEnd":2551,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/server/src/server/handlers/agents.ts#L2515-L2551","documentation":"The POST /agents/:agentId/approve-tool-call route requires a runId and toolCallId in the request body. The server validates them before resuming the agent run and throws HTTPException 400 when either is missing or empty. toolCallId identifies which pending tool invocation is being approved.","triggerScenarios":"POST to /agents/:agentId/approve-tool-call with a body omitting toolCallId (or sending it as empty string/undefined). The runId check on the same handler passes but toolCallId is absent.","commonSituations":"Hand-rolled curl/fetch calls against the approve endpoint; client SDK versions built before toolCallId was required; UI code forwarding only runId after a suspend event; copying a payload from a 'decline' flow that used different field names.","solutions":["Add toolCallId (the id of the suspended tool call, from the suspend chunk / suspended-runs response) to the request body","Verify the body matches approveToolCallBodySchema — send JSON with at least { runId, toolCallId }","Check the field is not an empty string; falsy values fail the check","Update @mastra/client-js / playground UI to a version that sends toolCallId"],"exampleFix":"// before\nawait fetch(`/api/agents/${agentId}/approve-tool-call`, { method: 'POST', body: JSON.stringify({ runId }) });\n// after\nawait fetch(`/api/agents/${agentId}/approve-tool-call`, { method: 'POST', body: JSON.stringify({ runId, toolCallId: pendingToolCall.id }) });","handlingStrategy":"validation","validationCode":"if (!runId || !toolCallId) throw new Error('approve-tool-call requires runId and toolCallId');","typeGuard":"function hasToolCallInput(p: unknown): p is { runId: string; toolCallId: string } {\n  return typeof p === 'object' && p !== null && typeof (p as any).runId === 'string' && (p as any).runId.length > 0 && typeof (p as any).toolCallId === 'string' && (p as any).toolCallId.length > 0;\n}","tryCatchPattern":"try { await approveToolCall({ runId, toolCallId }); } catch (e) { if (e instanceof MastraClientError && e.status === 400) console.error('Missing runId/toolCallId:', e.message); else throw e; }","preventionTips":["Store the toolCallId from the suspend chunk when the run suspends","Use the typed @mastra/client-js agent methods so required fields are enforced at compile time","Validate the approval payload against the route's body schema in client-side tests"],"tags":["http-400","missing-parameter","tool-approval","api"],"backgroundTag":"missing-required-parameter","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}