paperclipai/paperclip · error
Unsupported bridge body encoding.
Error message
Unsupported bridge body encoding.
What it means
decodeSandboxBridgeBody only accepts bodyEncoding values of undefined, 'utf8', or 'base64'. Any other declared encoding string causes this throw before any decoding is attempted. The check exists because the decoder would otherwise have to guess how the body bytes were encoded, and permissive fallbacks could silently corrupt binary payloads.
Solutions
- Change the producer to use bodyEncoding: 'base64' for binary data or omit bodyEncoding / use 'utf8' for text.
- Check the exact spelling of bodyEncoding — the accepted values are exactly 'utf8' and 'base64' (case-sensitive).
- Re-encode the body using Buffer.from(body, 'base64') on the producing side and declare bodyEncoding: 'base64'.
- Align encoder and decoder versions so both sides share the same sandbox-callback-bridge-body codec (see sandboxBridgeBodyCodecSource).
Example fix
// before
const envelope = { body: raw.toString("hex"), bodyEncoding: "hex" };
// after
const envelope = { body: raw.toString("base64"), bodyEncoding: "base64" }; Defensive patterns
Strategy: type-guard
Validate before calling
const ALLOWED_ENCODINGS = new Set([undefined, "utf8", "base64"]);
function hasSupportedEncoding(envelope) {
return ALLOWED_ENCODINGS.has(envelope?.bodyEncoding);
}
if (!hasSupportedEncoding(envelope)) throw new Error(`Unsupported bodyEncoding: ${envelope.bodyEncoding}`); Type guard
function hasKnownEncoding(en: unknown): en is { body: string; bodyEncoding?: "utf8" | "base64" } {
const e = en as { bodyEncoding?: unknown };
return typeof en === "object" && en !== null &&
(e.bodyEncoding === undefined || e.bodyEncoding === "utf8" || e.bodyEncoding === "base64");
} Try / catch
try {
const bytes = decodeSandboxBridgeBody(envelope, maxBodyBytes);
} catch (err) {
if (err instanceof Error && err.message === "Unsupported bridge body encoding.") {
throw new Error(`bodyEncoding '${envelope?.bodyEncoding}' not supported; use utf8 or base64`);
} else throw err;
} Prevention
- Use a shared union type ('utf8' | 'base64') for bodyEncoding so TypeScript rejects other values at compile time.
- Never use 'utf-8', 'hex', or 'binary' — only the exact strings 'utf8' and 'base64'.
- Share the codec via sandboxBridgeBodyCodecSource so encoder and decoder agree on supported encodings.
- Add a schema validator (e.g. zod enum) on the envelope before decoding.
When it happens
Trigger: Calling decodeSandboxBridgeBody with an envelope whose bodyEncoding is set to any string other than 'utf8' or 'base64' (e.g. 'hex', 'binary', 'utf-8' with a hyphen, or a typo like 'base36').
Common situations: A producer serializing with a different Buffer encoding name than the bridge contract supports; hand-written client code using 'utf-8' (invalid identifier here) instead of 'utf8'; version drift where a newer encoder emits an encoding the older shared decoder does not know.
Related errors
- Invalid bridge base64 body.
- Bridge body exceeded the configured size limit.
- Cloud runtime identity has an invalid
- Invalid bridge body.
- A full lowercase source SHA is required.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/d35d2fe7f0494c86.
Report an issue: GitHub.
Appendix: source
Thrown at packages/adapter-utils/src/sandbox-callback-bridge-body.ts:24
/** JSON can escape each input byte as six characters. Metadata is bounded too. */
export function sandboxBridgeEnvelopeLimit(maxBodyBytes: number): number {
return 6 * maxBodyBytes + 64 * 1024;
}
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)