paperclipai/paperclip · error · BridgeProcessCapacityError

The bridge host reached its reserved process body byte ceili

Error message

The bridge host reached its reserved process body byte ceiling. Retry later.

What it means

In the HTTP/2 bridge server, per-chunk reservation of a stream body against the shared process body ledger fails: BridgeProcessCapacityError ('reached its reserved process body byte ceiling'). Thrown from the chunk callback of readOrDrainHttp2StreamBody when a single incoming chunk cannot be reserved because the host-wide pool is exhausted by concurrent usage.

Source

Thrown at packages/adapter-utils/src/http2-bridge-server.ts:992

 * chunk joins the retained array, and reserves the concatenated buffer's own
 * byte count before `Buffer.concat` allocates it — the chunk array and the
 * concatenated buffer are two separate live copies, so both reserve. A
 * denied reservation rejects with {@link BridgeProcessCapacityError} and
 * destroys the stream, retaining no further chunk.
 */
function readHttp2StreamBody(
  stream: http2.ServerHttp2Stream,
  bounds: Http2BridgeBodyBounds,
  reservation?: BridgeBodyReservation,
): Promise<Buffer> {
  const chunks: Buffer[] = [];
  let retainedBytes = 0;
  return readOrDrainHttp2StreamBody(
    stream,
    bounds,
    (chunk, totalBytes) => {
      if (reservation && !reservation.reserve(chunk.byteLength)) {
        throw new BridgeProcessCapacityError();
      }
      chunks.push(chunk);
      retainedBytes = totalBytes;
    },
    () => {
      if (reservation && !reservation.reserve(retainedBytes)) {
        throw new BridgeProcessCapacityError();
      }
      return Buffer.concat(chunks);
    },
  );
}

/**
 * Drain and discard one denied stream's request body, under the same size,
 * idle, and lifetime bounds an authenticated request gets, but retaining no
 * chunk and reserving no bytes. `denyRequest` calls this instead of
 * {@link readHttp2StreamBody}, so a stream that never carries a valid bridge

View on GitHub (pinned to 01ad858492)

Solutions

  1. Retry the HTTP/2 request after a brief backoff; capacity frees as in-flight bodies are consumed and released.
  2. Audit reservation release paths (finally blocks) to eliminate leaked capacity from earlier failed reads.
  3. Throttle concurrent bridge streams or add admission control before reading bodies.
  4. Raise the reserved process body byte ceiling to match expected concurrency × body size.

Example fix

// before
if (reservation && !reservation.reserve(chunk.byteLength)) {
  throw new BridgeProcessCapacityError();
}
// after
if (reservation && !reservation.reserve(chunk.byteLength)) {
  stream.respond({ ':status': 503, 'retry-after': '2' });
  throw new BridgeProcessCapacityError();
}
Defensive patterns

Strategy: retry

Validate before calling

// Gate streams before reading: if advertised body exceeds per-stream share, reject early.
const cl = Number(headers["content-length"] ?? 0);
if (cl > maxBodyBytes / activeStreams) stream.respond({ ":status": 503, "retry-after": "2" });

Type guard

null

Try / catch

try {
  return await readOrDrainHttp2StreamBody(stream, bounds, onChunk, onFinalize);
} catch (err) {
  if (err instanceof BridgeProcessCapacityError) {
    stream.respond({ ":status": 503, "retry-after": "2" });
    return null;
  }
  throw err;
}

Prevention

When it happens

Trigger: An HTTP/2 stream body arrives while the bridge host's reserved process body byte pool is fully consumed by other in-flight requests; reservation.reserve(chunk.byteLength) returns false inside the onChunk callback.

Common situations: High concurrency on one bridge host; one slow client holding a large reservation while others arrive; misconfigured (too small) byte ceiling; leaked reservations from prior requests never released.

Related errors


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/75749761ff4dd3f3. Report an issue: GitHub.