vercel/ai · error · RelayRequestError

Host tool relay request is too large.

Error message

Host tool relay request is too large.

What it means

The host tool relay HTTP server reads the entire request body in readJSONBody and rejects any body larger than 16 MiB, responding with HTTP 413 via RelayRequestError. The relay is the local endpoint the ACP harness exposes so the agent process can call back into host-side MCP tools, so payloads are expected to stay small. This guard prevents unbounded memory use when a caller streams an oversized or runaway request.

Source

Thrown at packages/harness-acp/src/v1/bridge/host-tool-relay.ts:444

    Object.keys(value)
      .sort()
      .filter(key => value[key] !== undefined)
      .map(key => [key, canonicalizeJSON({ value: value[key] })]),
  );
}

async function readJSONBody({
  request,
}: {
  request: IncomingMessage;
}): Promise<unknown> {
  const chunks: Buffer[] = [];
  let size = 0;
  for await (const chunk of request) {
    const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
    size += buffer.length;
    if (size > 16 * 1024 * 1024) {
      throw new RelayRequestError({
        status: 413,
        message: 'Host tool relay request is too large.',
      });
    }
    chunks.push(buffer);
  }
  const text = Buffer.concat(chunks).toString('utf8');
  try {
    return await new Response(text, {
      headers: { 'content-type': 'application/json' },
    }).json();
  } catch {
    throw new RelayRequestError({
      status: 400,
      message: 'Host tool relay request is not valid JSON.',
    });
  }
}

View on GitHub (pinned to 69428b1f8b)

Solutions

  1. Reduce the size of the tool call arguments or results being sent to the relay (truncate or page large data, pass references instead of inline content).
  2. Check for accidental duplication of large payloads across looped tool calls and send only the delta.
  3. If you legitimately need larger payloads, host the tool call path outside the relay or chunk the data across multiple calls.

Example fix

// before
const result = { fileContents: await fs.readFile(hugeFile, 'utf8') };
await relay.callTool('read_file', result);
// after
const stat = await fs.stat(hugeFile);
const excerpt = (await fs.readFile(hugeFile, 'utf8')).slice(0, 100_000);
await relay.callTool('read_file', { size: stat.size, excerpt });
Defensive patterns

Strategy: validation

Validate before calling

function isWithinRelayLimit(payload: unknown): boolean {
  return Buffer.byteLength(JSON.stringify(payload), 'utf8') <= 16 * 1024 * 1024;
}
if (!isWithinRelayLimit(toolCall)) throw new Error('Relay payload exceeds 16 MiB');

Try / catch

try {
  await relay.callTool(name, args);
} catch (error) {
  if (RelayRequestError.isInstance(error) && error.status === 413) {
    // shrink/paginate the payload and retry
  }
  throw error;
}

Prevention

When it happens

Trigger: Any POST to the local host tool relay endpoint whose request body accumulates more than 16 * 1024 * 1024 bytes while readJSONBody iterates over the IncomingMessage stream, typically when a tool call sends huge arguments or tool results back through the relay.

Common situations: A tool implementation returning a very large result (big file contents, base64 blobs) that is relayed as the tool call payload; a misbehaving client retrying with the whole conversation embedded per call; accidental posting of binary or non-streamed data instead of a compact JSON envelope.

Related errors


AI-assisted analysis of vercel/ai@69428b1f8b (2026-08-30). Data as JSON: /api/errors/c74ed7d5ba9a5239. Report an issue: GitHub.