{"record":{"id":"498463a4875e5e9b","repo":"mastra-ai/mastra","slug":"mastra-livekit-mastrallm-requires-exactly-one-re","errorCode":null,"errorMessage":"@mastra/livekit: MastraLLM requires exactly one reply source — `remote`, `agent`, or `generate` — but got ${sources.length === 0 ? 'none' : sources.join(' + ')}.","messagePattern":"@mastra/livekit: MastraLLM requires exactly one reply source — `remote`, `agent`, or `generate` — but got (.+?)\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"integrations/livekit/src/llm-plugin.ts","lineNumber":136,"sourceCode":"  readonly #requestContext?: RequestContext;\n  /** Non-remote sources are built once; remote is built per turn so it can pick up `connOptions.timeoutMs`. */\n  readonly #staticGenerator?: VoiceReplyGenerator;\n  readonly #remoteOptions?: RemoteMastraAgentOptions & {\n    toolFeedback?: MastraLLMOptions['toolFeedback'];\n    onToolCall?: MastraLLMOptions['onToolCall'];\n    onTurnComplete?: VoiceTurnCompleteHook;\n  };\n  #warnedToolCtx = false;\n\n  constructor(options: MastraLLMOptions) {\n    super();\n    const sources = [\n      options.remote ? 'remote' : undefined,\n      options.agent ? 'agent' : undefined,\n      options.generate ? 'generate' : undefined,\n    ].filter(Boolean) as string[];\n    if (sources.length !== 1) {\n      throw new Error(\n        `@mastra/livekit: MastraLLM requires exactly one reply source — \\`remote\\`, \\`agent\\`, or \\`generate\\` — ` +\n          `but got ${sources.length === 0 ? 'none' : sources.join(' + ')}.`,\n      );\n    }\n\n    this.#memory = options.memory ?? false;\n    this.#requestContext = toRequestContext(options.requestContext);\n\n    if (options.remote) {\n      this.#model = options.remote.agentId;\n      this.#remoteOptions = {\n        ...options.remote,\n        toolFeedback: options.toolFeedback,\n        onToolCall: options.onToolCall,\n        onTurnComplete: options.onTurnComplete,\n      };\n    } else if (options.agent) {\n      this.#model = options.agent.id ?? options.agent.name;","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/integrations/livekit/src/llm-plugin.ts#L118-L154","documentation":"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.","triggerScenarios":"new MastraLLM({}) with no reply source; or passing two/three of remote, agent, generate together (e.g. remote + generate).","commonSituations":"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.","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."],"exampleFix":"// before\nconst llm = new MastraLLM({ remote: { agentId: 'support' }, agent: mastra.getAgent('support') });\n// after\nconst llm = new MastraLLM({ remote: { agentId: 'support' } });","handlingStrategy":"validation","validationCode":"function validateReplySource(options) {\n  const provided = ['remote', 'agent', 'generate'].filter(k => options[k] != null);\n  if (provided.length !== 1) throw new Error(`MastraLLM needs exactly one reply source, got: ${provided.join('+') || 'none'}`);\n}\nvalidateReplySource(myOptions); // before new MastraLLM(myOptions)","typeGuard":null,"tryCatchPattern":"let llm;\ntry {\n  llm = new MastraLLM(options);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('exactly one reply source')) {\n    console.error('Bad MastraLLM options keys:', Object.keys(options));\n  }\n  throw e;\n}","preventionTips":["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."],"tags":["configuration","validation","livekit","llm-plugin"],"backgroundTag":"invalid-configuration-conflict","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}