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.

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.

Appendix: 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)