ruvnet/ruflo · error

fetchAgentCard: card exceeds ${maxBytes} bytes

Error message

fetchAgentCard: card exceeds ${maxBytes} bytes

What it means

Anti-bloat guard in fetchAgentCard(): after the response body is read, if the text exceeds options.maxBytes (default 256 KiB, measured on the decoded string length) the card is refused before JSON parsing. This bounds memory and blocks padded or malicious card payloads.

Source

Thrown at v3/@claude-flow/plugin-agent-federation/src/a2a/consume.ts:70

  const maxBytes = options.maxBytes ?? 256 * 1024;

  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 10_000);
  let text: string;
  try {
    const res = await fetchImpl(sourceUrl, {
      signal: controller.signal,
      headers: { accept: 'application/json' },
    });
    if (!res.ok) {
      throw new Error(`fetchAgentCard: ${sourceUrl} returned HTTP ${res.status}`);
    }
    text = await res.text();
  } finally {
    clearTimeout(timer);
  }
  if (text.length > maxBytes) {
    throw new Error(`fetchAgentCard: card exceeds ${maxBytes} bytes`);
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(text);
  } catch {
    throw new Error(`fetchAgentCard: ${sourceUrl} did not return valid JSON`);
  }

  const validation = validateAgentCard(parsed);
  if (!validation.valid) {
    throw new Error(
      `fetchAgentCard: invalid A2A agent card from ${sourceUrl}: ${validation.errors.join('; ')}`,
    );
  }
  return { card: parsed as A2AAgentCard, sourceUrl };
}

View on GitHub (pinned to fa13ee4ad6)

Solutions

  1. Inspect the URL manually — oversized responses often mean the wrong endpoint is being served
  2. Raise the cap consciously via options.maxBytes if the card is legitimately larger
  3. Reduce card size on the serving side (strip base64 assets, shorten metadata)
  4. If sizes are unpredictable, pre-flight with a HEAD request and check content-length before fetching

Example fix

// before
await fetchAgentCard(url);
// after
await fetchAgentCard(url, { maxBytes: 1024 * 1024 }); // explicit, conscious cap
Defensive patterns

Strategy: validation

Validate before calling

// pre-flight size via HEAD so you never read an oversized body
const head = await fetch(cardUrl, { method: 'HEAD' });
const len = Number(head.headers.get('content-length'));
if (Number.isFinite(len) && len > MAX_BYTES) {
  throw new RangeError('agent card too large before download');
}
await fetchAgentCard(base, { maxBytes: MAX_BYTES });

Try / catch

try {
  await fetchAgentCard(base, opts);
} catch (e) {
  if (String(e).includes('card exceeds')) {
    // decide consciously: raise the cap or reject this peer
    await fetchAgentCard(base, { ...opts, maxBytes: MAX_BYTES * 4 });
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: A peer serving a legitimately large card (inlined base64 icons, very long descriptions/metadata arrays) past the default cap; a misconfigured server returning a huge JSON (e.g. an app bundle on the wrong route); an adversarial peer deliberately padding the card.

Common situations: Defaulting maxBytes while fetching from peers with verbose cards; gateways that append banners or wrap responses; cards that embed full capability catalogs.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/ba91a44f0a90d352. Report an issue: GitHub.