mastra-ai/mastra · error
@mastra/livekit: the agent requested tool approval or suspen
Error message
@mastra/livekit: the agent requested tool approval or suspended a tool call; human-in-the-loop flows (approve-tool-call / resume-stream) are not supported on the voice path. Remove requireApproval or suspend from the tools this agent uses on voice calls.
What it means
While consuming the Mastra agent's stream, the generator received a 'tool-call-approval' or 'tool-call-suspended' event, meaning the agent uses a tool with requireApproval or a suspend-based human-in-the-loop flow. Voice paths have no UI to approve/resume, so the library aborts with this explicit error instead of stalling the call.
Source
Thrown at integrations/livekit/src/remote.ts:339
break;
}
case 'finish': {
clearWatchdog();
const output = payload.output as { usage?: unknown } | undefined;
const turnUsage = mapTurnUsage(output?.usage);
if (turnUsage) {
usage = turnUsage;
try {
ctx.onUsage?.(turnUsage);
} catch (error) {
console.warn('@mastra/livekit: onUsage hook threw', error);
}
}
break;
}
case 'tool-call-approval':
case 'tool-call-suspended':
throw new Error(HITL_UNSUPPORTED_MESSAGE);
case 'error': {
const error = payload.error;
throw error instanceof Error ? error : new Error(String(error));
}
default:
break; // ignore everything else (text-start, step-start, tool-result, ...)
}
}
clearWatchdog();
break; // success, or a clean barge-in break out of the SSE loop
} catch (error) {
clearWatchdog();
if (cancelled) break; // barge-in: not a failure, emit interrupted below
// Classify into the LiveKit error vocabulary. Application errors thrown after streaming
// began (an `error` chunk, a HITL chunk) are not connection failures — propagate as-is.
let typed: APIError;
if (timedOut) {View on GitHub (pinned to 75dd419e61)
Solutions
- Remove requireApproval from the tools used by the agent on voice calls.
- Refactor the tool to not suspend (execute fully inline) for the voice path, or provide a separate voice-specific agent without HITL tools.
- If approval is essential, handle that action outside the voice flow (e.g. a chat channel) rather than via the LiveKit worker.
Example fix
// before
createTool({ id: 'transferFunds', requireApproval: true, execute: ... });
// after
createTool({ id: 'transferFunds', execute: ... }); // no approval for voice path Defensive patterns
Strategy: validation
Validate before calling
function assertNoHitlTools(agent) {
for (const tool of agent.getTools()) {
if (tool.requireApproval) throw new Error(`Tool ${tool.id} requires approval — unsupported on voice path`);
}
}
assertNoHitlTools(voiceAgent); // before assigning agent to a voice worker Try / catch
try {
await runVoiceTurn(ctx);
} catch (e) {
if (e instanceof Error && e.message.includes('tool approval')) {
// route the caller to a non-voice channel; do not retry
notifyCallerOfChannelFallback();
} else throw e;
} Prevention
- Keep voice-serving agents free of requireApproval/suspend-based tools.
- Maintain separate agent variants for chat (with HITL) and voice (without).
- Add a startup check that walks the voice agent's tools and rejects approval-requiring ones.
- Document which shared tools are voice-safe.
When it happens
Trigger: An agent used on a LiveKit voice call has a tool configured with requireApproval: true, or its execute calls tool suspension (suspend()) awaiting resume; the stream then emits the approval/suspended event during a voice turn.
Common situations: Reusing a chat agent (with HITL tools) as a voice agent; adding a 'confirm before action' tool to an agent that also serves voice calls.
Related errors
- @mastra/livekit: reply generation runs through the Mastra ag
- CursorSDKAgent does not support structuredOutput because the
- @mastra/livekit: MastraVoiceAgent requires `agent` or `gener
- @mastra/livekit: MastraVoiceAgent requires `agent` or `gener
- @mastra/livekit: set LIVEKIT_URL or pass serverUrl to dispat
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/44fa5653e799a167.
Report an issue: GitHub.