mastra-ai/mastra · error
@mastra/livekit: MastraLLM requires exactly one reply source
Error message
@mastra/livekit: MastraLLM requires exactly one reply source — `remote`, `agent`, or `generate` — but got ${sources.length === 0 ? 'none' : sources.join(' + ')}. What it means
MastraLLM (LiveKit LLM plugin) must have exactly one way to produce replies: streaming from a remote Mastra agent (`remote`), using a local Mastra agent (`agent`), or a custom generate function (`generate`). The constructor counts which of the three options were provided and throws when the count is not exactly 1 — either none or more than one was supplied.
Source
Thrown at integrations/livekit/src/llm-plugin.ts:136
readonly #requestContext?: RequestContext;
/** Non-remote sources are built once; remote is built per turn so it can pick up `connOptions.timeoutMs`. */
readonly #staticGenerator?: VoiceReplyGenerator;
readonly #remoteOptions?: RemoteMastraAgentOptions & {
toolFeedback?: MastraLLMOptions['toolFeedback'];
onToolCall?: MastraLLMOptions['onToolCall'];
onTurnComplete?: VoiceTurnCompleteHook;
};
#warnedToolCtx = false;
constructor(options: MastraLLMOptions) {
super();
const sources = [
options.remote ? 'remote' : undefined,
options.agent ? 'agent' : undefined,
options.generate ? 'generate' : undefined,
].filter(Boolean) as string[];
if (sources.length !== 1) {
throw new Error(
`@mastra/livekit: MastraLLM requires exactly one reply source — \`remote\`, \`agent\`, or \`generate\` — ` +
`but got ${sources.length === 0 ? 'none' : sources.join(' + ')}.`,
);
}
this.#memory = options.memory ?? false;
this.#requestContext = toRequestContext(options.requestContext);
if (options.remote) {
this.#model = options.remote.agentId;
this.#remoteOptions = {
...options.remote,
toolFeedback: options.toolFeedback,
onToolCall: options.onToolCall,
onTurnComplete: options.onTurnComplete,
};
} else if (options.agent) {
this.#model = options.agent.id ?? options.agent.name;View on GitHub (pinned to 75dd419e61)
Solutions
- Pick the single intended reply source and keep only its option (remote, agent, or generate) in the constructor options.
- If you meant to stream from a remote Mastra agent, keep only `remote` and remove `agent`/`generate`.
- If you see 'got none', pass one of the three options instead of an empty object.
Example fix
// before
const llm = new MastraLLM({ remote: { agentId: 'support' }, agent: mastra.getAgent('support') });
// after
const llm = new MastraLLM({ remote: { agentId: 'support' } }); Defensive patterns
Strategy: validation
Validate before calling
function validateReplySource(options) {
const provided = ['remote', 'agent', 'generate'].filter(k => options[k] != null);
if (provided.length !== 1) throw new Error(`MastraLLM needs exactly one reply source, got: ${provided.join('+') || 'none'}`);
}
validateReplySource(myOptions); // before new MastraLLM(myOptions) Try / catch
let llm;
try {
llm = new MastraLLM(options);
} catch (e) {
if (e instanceof Error && e.message.includes('exactly one reply source')) {
console.error('Bad MastraLLM options keys:', Object.keys(options));
}
throw e;
} Prevention
- Build MastraLLM options through a helper that enforces exactly one source.
- When switching between remote/agent/generate, delete the old key instead of commenting it out.
- Type the options as a discriminated union (XOR of remote|agent|generate) so TypeScript rejects multiple sources.
When it happens
Trigger: new MastraLLM({}) with no reply source; or passing two/three of remote, agent, generate together (e.g. remote + generate).
Common situations: Copy-pasting example code that keeps both `agent` and `remote` options; refactoring from a local agent to remote streaming and forgetting to remove the old option; instantiating the plugin with an empty options object.
Related errors
- @mastra/livekit: set exactly one reply generator — `generate
- @mastra/livekit: set `agent` or `workflow`, not both — they
- @mastra/livekit: `workflowInput` is required when `workflow`
- @mastra/livekit: `configuration.endCall` has no effect with
- Google RBAC roleMapping is required.
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/498463a4875e5e9b.
Report an issue: GitHub.