paperclipai/paperclip · error

Plugin API request body is too large

Error message

Plugin API request body is too large

What it means

Returned as HTTP 413 when Buffer.byteLength(JSON.stringify(requestBody)) exceeds PLUGIN_API_BODY_LIMIT_BYTES, which is 1,000,000 bytes (~1 MB). The check runs on the parsed body after auth/company/checkout guards, so even structurally valid JSON is rejected purely for size before the request is forwarded to the plugin worker.

Source

Thrown at server/src/routes/plugins.ts:1887

    }

    try {
      assertScopedApiAuth(req, match.route);
      const companyId = await resolveScopedApiCompanyId(match.route, match.params, req);
      if (!companyId) {
        res.status(400).json({ error: "Unable to resolve company for plugin API route" });
        return;
      }
      assertCompanyAccess(req, companyId);
      await enforceScopedApiCheckout(req, match.route, match.params, companyId);
      if (req.method !== "GET" && req.headers["content-type"] && !req.is("application/json")) {
        res.status(415).json({ error: "Plugin API routes accept JSON requests only" });
        return;
      }
      const requestBody = req.body ?? null;
      const bodySize = Buffer.byteLength(JSON.stringify(requestBody));
      if (bodySize > PLUGIN_API_BODY_LIMIT_BYTES) {
        res.status(413).json({ error: "Plugin API request body is too large" });
        return;
      }

      const actor = getActorInfo(req);
      const input: PluginScopedApiRequest = {
        routeKey: match.route.routeKey,
        method: req.method,
        path: requestPath,
        params: match.params,
        query: normalizeQuery(req.query),
        body: requestBody,
        actor: {
          actorType: actor.actorType,
          actorId: actor.actorId,
          agentId: actor.agentId,
          userId: actor.actorType === "user" ? actor.actorId : null,
          runId: actor.runId,
        },

View on GitHub (pinned to a7e689b3c3)

Solutions

  1. Split the payload into multiple requests each comfortably under 1 MB and batch server-side.
  2. Upload large blobs to object storage or a dedicated upload endpoint and pass a reference (URL/key) in the plugin API body.
  3. Trim redundant or computed fields from the JSON before sending.

Example fix

// before
await fetch(url, { method: "POST", headers, body: JSON.stringify({ items: allItems }) });

// after
function chunk<T>(arr: T[], n: number): T[][] {
  const out: T[][] = [];
  for (let i = 0; i < arr.length; i += n) out.push(arr.slice(i, i + n));
  return out;
}
for (const batch of chunk(allItems, 200)) {
  await fetch(url, { method: "POST", headers, body: JSON.stringify({ items: batch }) });
}
Defensive patterns

Strategy: validation

Validate before calling

const PLUGIN_API_BODY_LIMIT_BYTES = 1_000_000;
function assertBodyWithinLimit(body: unknown): void {
  const size = Buffer.byteLength(JSON.stringify(body));
  if (size > PLUGIN_API_BODY_LIMIT_BYTES) {
    throw new Error(`Body is ${size} bytes; plugin API limit is ${PLUGIN_API_BODY_LIMIT_BYTES}`);
  }
}

Type guard

function fitsPluginApiLimit(body: unknown): boolean {
  try { return Buffer.byteLength(JSON.stringify(body)) <= 1_000_000; }
  catch { return false; }
}

Prevention

When it happens

Trigger: POST to /api/plugins/:pluginId/api/* with a JSON payload over ~1 MB: large batch arrays, base64-encoded file contents embedded in JSON, or deeply populated bulk-import payloads.

Common situations: Bulk import/sync endpoints exposed as plugin API routes; clients inlining images or documents as base64; generated clients that echo entire collections in one request.

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 paperclipai/paperclip@a7e689b3c3 (2026-08-18). Data as JSON: /api/errors/df571c2d5aaf6873. Report an issue: GitHub.