mastra-ai/mastra · error

@mastra/livekit: no fetch implementation available; pass `fe

Error message

@mastra/livekit: no fetch implementation available; pass `fetch` or run on Node ≥ 22.

What it means

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.

Source

Thrown at integrations/livekit/src/remote.ts:182

 * indefinite dead air.
 */
export function createRemoteAgentReplyGenerator(options: RemoteAgentReplyGeneratorOptions): VoiceReplyGenerator {
  const {
    baseUrl,
    agentId,
    apiPrefix = DEFAULT_API_PREFIX,
    headers,
    fetch: fetchImpl = globalThis.fetch,
    timeoutMs = DEFAULT_REMOTE_TIMEOUT_MS,
    retries = DEFAULT_REMOTE_RETRIES,
    body: extraBody,
    toolFeedback,
    onToolCall,
    onTurnComplete,
  } = options;

  if (!fetchImpl) {
    throw new Error('@mastra/livekit: no fetch implementation available; pass `fetch` or run on Node ≥ 22.');
  }
  const url = `${trimTrailingSlash(baseUrl)}${apiPrefix}/agents/${agentId}/stream`;

  return ctx => {
    if (ctx.messages.length === 0) return null;

    // Reassigned per retry attempt (see the loop below) so a watchdog abort on one attempt can't
    // poison the next; `cancel()` always aborts whichever attempt is currently in flight.
    let currentAbortController: AbortController | undefined;
    let cancelled = false;
    // Accumulated as the turn streams so the post-turn hook sees what was actually produced.
    let replyText = '';
    const toolCalls: VoiceToolCall[] = [];
    let usage: VoiceTurnUsage | undefined;

    const emitTurnComplete = (interrupted: boolean) => {
      if (!onTurnComplete) return;
      const completeCtx: VoiceTurnCompleteContext = {

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Run on Node 22 or newer, where global fetch satisfies the requirement.
  2. Pass an explicit fetch implementation via the `fetch` option (e.g. undici's fetch or node-fetch).
  3. Install a fetch polyfill that sets globalThis.fetch before creating the reply generator.

Example fix

// before
createRemoteAgentReplyGenerator({ baseUrl, agentId }); // Node 20
// after
import { fetch } from 'undici';
createRemoteAgentReplyGenerator({ baseUrl, agentId, fetch });
Defensive patterns

Strategy: validation

Validate before calling

if (typeof fetch !== 'function') {
  throw new Error('This runtime has no global fetch; upgrade to Node >= 22 or pass a `fetch` option.');
}
// then safely:
createRemoteAgentReplyGenerator({ baseUrl, agentId });

Type guard

function hasFetch(r): r is typeof globalThis & { fetch: typeof fetch } {
  return typeof (r as { fetch?: unknown }).fetch === 'function';
}

Try / catch

try {
  const gen = createRemoteAgentReplyGenerator(opts);
} catch (e) {
  if (e instanceof Error && e.message.includes('no fetch implementation')) {
    const gen = createRemoteAgentReplyGenerator({ ...opts, fetch: (await import('undici')).fetch });
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/04568621c56837fa. Report an issue: GitHub.