paperclipai/paperclip · error
Invalid bridge base64 body.
Error message
Invalid bridge base64 body.
What it means
The bridge decoder does not trust Buffer.from(value, 'base64') because it is permissive and silently skips invalid characters. Before decoding, it validates strict base64 shape (length divisible by 4, only [A-Za-z0-9+/=], padding only as a final = or ==); after decoding, it round-trips (bytes.toString('base64') === value) to catch any residual ambiguity such as misplaced padding or non-canonical encodings. Either check failing throws 'Invalid bridge base64 body.'
Solutions
- Re-encode the body on the producer with Buffer.from(bytes).toString('base64') so it is canonical padded standard base64.
- Strip whitespace/newlines and convert URL-safe characters ('-' -> '+', '_' -> '/') before sending, or switch the producer to standard base64.
- Check for truncation: length must be a multiple of 4 with at most two trailing '=' characters.
- Diff the round-trip: compare Buffer.from(value, 'base64').toString('base64') with the original string locally to pinpoint the corruption.
Example fix
// before
const body = raw.toString("base64url").replace(/=+$/, ""); // non-canonical, unpadded
// after
const body = raw.toString("base64"); // canonical padded standard base64
const envelope = { body, bodyEncoding: "base64" }; Defensive patterns
Strategy: validation
Validate before calling
function isCanonicalBase64(value) {
return typeof value === "string" && value.length % 4 === 0 &&
/^[A-Za-z0-9+/]*={0,2}$/.test(value) &&
Buffer.from(value, "base64").toString("base64") === value;
}
if (envelope.bodyEncoding === "base64" && !isCanonicalBase64(envelope.body)) throw new Error("body must be canonical padded base64"); Type guard
function isCanonicalBase64(value: unknown): value is string {
return typeof value === "string" && value.length % 4 === 0 &&
/^[A-Za-z0-9+/]*={0,2}$/.test(value) &&
Buffer.from(value, "base64").toString("base64") === value;
} Try / catch
try {
const bytes = decodeSandboxBridgeBody(envelope, maxBodyBytes);
} catch (err) {
if (err instanceof Error && err.message === "Invalid bridge base64 body.") {
throw new Error("Producer sent malformed base64; re-encode with Buffer.toString('base64')");
} else throw err;
} Prevention
- Always produce base64 with Buffer.toString('base64') — never hand-roll or strip padding.
- Convert URL-safe base64 ('-','_') to standard ('+','/') and restore padding before sending.
- Strip whitespace/newlines from base64 payloads before embedding in the envelope.
- Unit-test the producer's encoding with the same round-trip check the decoder uses.
When it happens
Trigger: bodyEncoding is 'base64' and the body string: has length not divisible by 4; contains characters outside the base64 alphabet; has padding characters not exactly at the end (0, 1, or 2 trailing '=' allowed); or decodes to bytes whose re-encoding does not reproduce the original string (non-canonical encoding, misplaced '=').
Common situations: A producer truncates a base64 string mid-encoding; URL-safe base64 ('-' and '_') sent instead of standard base64; padding stripped by a JSON layer or manual string manipulation; whitespace/newlines embedded in the base64 body; double-encoding or corrupting the payload during transport.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Unsupported bridge body encoding.
- Bridge body exceeded the configured size limit.
- Invalid bridge body.
- A full lowercase source SHA is required.
- A reusable lease cannot be replaced and reacquired in the…
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/4bc31e1e6f0a4a53.
Report an issue: GitHub.
Appendix: source
Thrown at packages/adapter-utils/src/sandbox-callback-bridge-body.ts:29
export function encodeSandboxBridgeBody(body: string | Buffer, maxBodyBytes: number): SandboxCallbackBridgeBody {
if (Buffer.byteLength(body) > maxBodyBytes) throw new Error("Bridge body exceeded the configured size limit.");
return Buffer.isBuffer(body) ? { body: body.toString("base64"), bodyEncoding: "base64" } : { body };
}
/** Self-contained so the same decoder can be embedded in the remote gateway. */
export function decodeSandboxBridgeBody(envelope: SandboxCallbackBridgeBody, maxBodyBytes: number): Buffer {
if (!envelope || typeof envelope.body !== "string") throw new Error("Invalid bridge body.");
if (envelope.bodyEncoding === undefined || envelope.bodyEncoding === "utf8") {
if (Buffer.byteLength(envelope.body, "utf8") > maxBodyBytes) throw new Error("Bridge body exceeded the configured size limit.");
return Buffer.from(envelope.body, "utf8");
}
if (envelope.bodyEncoding !== "base64") throw new Error("Unsupported bridge body encoding.");
const value = envelope.body;
if (value.length > 4 * Math.ceil(maxBodyBytes / 3)) throw new Error("Bridge body exceeded the configured size limit.");
// Buffer.from is permissive; reject malformed input before allocating bytes.
if (value.length % 4 !== 0 || /[^A-Za-z0-9+/=]/.test(value) || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
throw new Error("Invalid bridge base64 body.");
}
const bytes = Buffer.from(value, "base64");
if (bytes.length > maxBodyBytes) throw new Error("Bridge body exceeded the configured size limit.");
if (bytes.toString("base64") !== value) throw new Error("Invalid bridge base64 body.");
return bytes;
}
export function sandboxBridgeBodyCodecSource(): string {
return [sandboxBridgeEnvelopeLimit, encodeSandboxBridgeBody, decodeSandboxBridgeBody]
.map(fn => `const ${fn.name} = ${fn.toString()};`).join("\n");
}
View on GitHub (pinned to 3f1d897a7c)