mastra-ai/mastra · error
@mastra/livekit: set `agent` or `workflow`, not both — they
Error message
@mastra/livekit: set `agent` or `workflow`, not both — they are mutually exclusive reply generators.
What it means
`agent` and `workflow` are both reply generators for the LiveKit worker and cannot be combined. If both are set, the worker cannot determine which one should handle each turn, so it throws immediately during worker creation.
Source
Thrown at integrations/livekit/src/worker.ts:788
* mastra,
* stt: 'deepgram/nova-3',
* tts: 'cartesia/sonic-3',
* turnDetection: 'multilingual',
* });
*
* if (process.argv[1] === fileURLToPath(import.meta.url)) {
* runLiveKitWorker({ entry: import.meta.url, agentName: 'mastra-voice' });
* }
* ```
*/
export function createLiveKitWorker(options: CreateLiveKitWorkerOptions) {
if (options.generate && (options.agent || options.workflow)) {
throw new Error(
'@mastra/livekit: set exactly one reply generator — `generate`, `agent`, or `workflow` — not a combination.',
);
}
if (options.agent && options.workflow) {
throw new Error(
'@mastra/livekit: set `agent` or `workflow`, not both — they are mutually exclusive reply generators.',
);
}
if (options.workflow && !options.workflowInput) {
throw new Error(
'@mastra/livekit: `workflowInput` is required when `workflow` is set. Map the turn into the ' +
'workflow inputData, e.g. workflowInput: ({ chatCtx }) => ({ history: chatContextToMessages(chatCtx) }).',
);
}
if (options.generate && options.configuration?.endCall) {
throw new Error(
'@mastra/livekit: `configuration.endCall` has no effect with `generate` — the worker cannot observe ' +
'tool calls from a custom reply generator. Detect the end-call tool inside your generator and call ' +
'`runEndCall` directly instead.',
);
}
const wantsSileroVad = options.vad === undefined || options.vad === 'silero';View on GitHub (pinned to 75dd419e61)
Solutions
- Remove either `agent` or `workflow`, keeping the one you want to run.
- If you genuinely need both behaviors, route internally: e.g. run the workflow inside the `generate` callback so only one generator option is set.
Example fix
// before
createLiveKitWorker({ agent: myAgent, workflow: myWorkflow });
// after
createLiveKitWorker({ workflow: myWorkflow, workflowInput: ({ chatCtx }) => ({ history: chatContextToMessages(chatCtx) }) }); Defensive patterns
Strategy: validation
Validate before calling
if (options.agent && options.workflow) throw new Error('Choose either agent or workflow, not both, before creating the LiveKit worker'); Type guard
function hasExclusiveReplyHandler(o: { agent?: unknown; workflow?: unknown }): boolean {
return !(o.agent != null && o.workflow != null);
} Try / catch
try {
const worker = createLiveKitWorker(options);
} catch (e) {
if ((e as Error).message.includes('mutually exclusive reply generators')) {
console.error('Set either agent or workflow, not both');
} else throw e;
} Prevention
- Use a discriminated union option type keyed on the generator kind
- If you need agent+workflow behavior, wrap the workflow inside a single generate callback
- Keep one source of truth for reply handling in config files
When it happens
Trigger: createLiveKitWorker({ agent: someAgent, workflow: someWorkflow }) — both options defined, with or without `generate`.
Common situations: Migrating a voice pipeline from agents to workflows while both fields linger; a generic factory that blindly assigns all configured handlers to options; copying sample code that mentions both options.
Related errors
- @mastra/livekit: set exactly one reply generator — `generate
- terminationGraceMs must be greater than zero.
- Worker command must be a non-empty executable path.
- ${name} must be greater than zero.
- Unknown worker resource limit: ${name}.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/615e5a8f6531ce87.
Report an issue: GitHub.