{"record":{"id":"04568621c56837fa","repo":"mastra-ai/mastra","slug":"mastra-livekit-no-fetch-implementation-available","errorCode":null,"errorMessage":"@mastra/livekit: no fetch implementation available; pass `fetch` or run on Node ≥ 22.","messagePattern":"@mastra/livekit: no fetch implementation available; pass `fetch` or run on Node ≥ 22\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"integrations/livekit/src/remote.ts","lineNumber":182,"sourceCode":" * indefinite dead air.\n */\nexport function createRemoteAgentReplyGenerator(options: RemoteAgentReplyGeneratorOptions): VoiceReplyGenerator {\n  const {\n    baseUrl,\n    agentId,\n    apiPrefix = DEFAULT_API_PREFIX,\n    headers,\n    fetch: fetchImpl = globalThis.fetch,\n    timeoutMs = DEFAULT_REMOTE_TIMEOUT_MS,\n    retries = DEFAULT_REMOTE_RETRIES,\n    body: extraBody,\n    toolFeedback,\n    onToolCall,\n    onTurnComplete,\n  } = options;\n\n  if (!fetchImpl) {\n    throw new Error('@mastra/livekit: no fetch implementation available; pass `fetch` or run on Node ≥ 22.');\n  }\n  const url = `${trimTrailingSlash(baseUrl)}${apiPrefix}/agents/${agentId}/stream`;\n\n  return ctx => {\n    if (ctx.messages.length === 0) return null;\n\n    // Reassigned per retry attempt (see the loop below) so a watchdog abort on one attempt can't\n    // poison the next; `cancel()` always aborts whichever attempt is currently in flight.\n    let currentAbortController: AbortController | undefined;\n    let cancelled = false;\n    // Accumulated as the turn streams so the post-turn hook sees what was actually produced.\n    let replyText = '';\n    const toolCalls: VoiceToolCall[] = [];\n    let usage: VoiceTurnUsage | undefined;\n\n    const emitTurnComplete = (interrupted: boolean) => {\n      if (!onTurnComplete) return;\n      const completeCtx: VoiceTurnCompleteContext = {","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/integrations/livekit/src/remote.ts#L164-L200","documentation":"createRemoteAgentReplyGenerator posts to the Mastra agent stream endpoint over HTTP and needs a fetch implementation. If no explicit `fetch` option was supplied and the runtime does not expose a global fetch (Node < 22 without a polyfill, or a runtime without fetch), it throws instead of failing later at request time.","triggerScenarios":"Calling createRemoteAgentReplyGenerator (directly or via the MastraLLM `remote` option) on Node < 22 or an environment without global fetch, without passing a `fetch` implementation in options.","commonSituations":"Running voice workers on Node 18/20 where global fetch is experimental or absent per the library's requirement; bundling for edge runtimes that lack fetch under the expected global; polyfills not installed.","solutions":["Run on Node 22 or newer, where global fetch satisfies the requirement.","Pass an explicit fetch implementation via the `fetch` option (e.g. undici's fetch or node-fetch).","Install a fetch polyfill that sets globalThis.fetch before creating the reply generator."],"exampleFix":"// before\ncreateRemoteAgentReplyGenerator({ baseUrl, agentId }); // Node 20\n// after\nimport { fetch } from 'undici';\ncreateRemoteAgentReplyGenerator({ baseUrl, agentId, fetch });","handlingStrategy":"validation","validationCode":"if (typeof fetch !== 'function') {\n  throw new Error('This runtime has no global fetch; upgrade to Node >= 22 or pass a `fetch` option.');\n}\n// then safely:\ncreateRemoteAgentReplyGenerator({ baseUrl, agentId });","typeGuard":"function hasFetch(r): r is typeof globalThis & { fetch: typeof fetch } {\n  return typeof (r as { fetch?: unknown }).fetch === 'function';\n}","tryCatchPattern":"try {\n  const gen = createRemoteAgentReplyGenerator(opts);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('no fetch implementation')) {\n    const gen = createRemoteAgentReplyGenerator({ ...opts, fetch: (await import('undici')).fetch });\n  } else throw e;\n}","preventionTips":["Pin engines.node >= 22 in package.json for voice worker services.","Centralize fetch resolution (undici/node-fetch fallback) in one config module.","Add a startup smoke check that global fetch exists before spawning workers."],"tags":["environment","network","runtime-compatibility","livekit"],"backgroundTag":"fetch-not-available","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}