{"record":{"id":"d35d2fe7f0494c86","repo":"paperclipai/paperclip","slug":"unsupported-bridge-body-encoding","errorCode":null,"errorMessage":"Unsupported bridge body encoding.","messagePattern":"Unsupported bridge body encoding\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/adapter-utils/src/sandbox-callback-bridge-body.ts","lineNumber":24,"sourceCode":"\n/** JSON can escape each input byte as six characters. Metadata is bounded too. */\nexport function sandboxBridgeEnvelopeLimit(maxBodyBytes: number): number {\n  return 6 * maxBodyBytes + 64 * 1024;\n}\n\nexport function encodeSandboxBridgeBody(body: string | Buffer, maxBodyBytes: number): SandboxCallbackBridgeBody {\n  if (Buffer.byteLength(body) > maxBodyBytes) throw new Error(\"Bridge body exceeded the configured size limit.\");\n  return Buffer.isBuffer(body) ? { body: body.toString(\"base64\"), bodyEncoding: \"base64\" } : { body };\n}\n\n/** Self-contained so the same decoder can be embedded in the remote gateway. */\nexport function decodeSandboxBridgeBody(envelope: SandboxCallbackBridgeBody, maxBodyBytes: number): Buffer {\n  if (!envelope || typeof envelope.body !== \"string\") throw new Error(\"Invalid bridge body.\");\n  if (envelope.bodyEncoding === undefined || envelope.bodyEncoding === \"utf8\") {\n    if (Buffer.byteLength(envelope.body, \"utf8\") > maxBodyBytes) throw new Error(\"Bridge body exceeded the configured size limit.\");\n    return Buffer.from(envelope.body, \"utf8\");\n  }\n  if (envelope.bodyEncoding !== \"base64\") throw new Error(\"Unsupported bridge body encoding.\");\n  const value = envelope.body;\n  if (value.length > 4 * Math.ceil(maxBodyBytes / 3)) throw new Error(\"Bridge body exceeded the configured size limit.\");\n  // Buffer.from is permissive; reject malformed input before allocating bytes.\n  if (value.length % 4 !== 0 || /[^A-Za-z0-9+/=]/.test(value) || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {\n    throw new Error(\"Invalid bridge base64 body.\");\n  }\n  const bytes = Buffer.from(value, \"base64\");\n  if (bytes.length > maxBodyBytes) throw new Error(\"Bridge body exceeded the configured size limit.\");\n  if (bytes.toString(\"base64\") !== value) throw new Error(\"Invalid bridge base64 body.\");\n  return bytes;\n}\n\nexport function sandboxBridgeBodyCodecSource(): string {\n  return [sandboxBridgeEnvelopeLimit, encodeSandboxBridgeBody, decodeSandboxBridgeBody]\n    .map(fn => `const ${fn.name} = ${fn.toString()};`).join(\"\\n\");\n}\n","sourceCodeStart":6,"sourceCodeEnd":41,"githubUrl":"https://github.com/paperclipai/paperclip/blob/3f1d897a7c018d76563a21c6e39c3c9b03933622/packages/adapter-utils/src/sandbox-callback-bridge-body.ts#L6-L41","documentation":"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.","triggerScenarios":"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').","commonSituations":"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.","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)."],"exampleFix":"// before\nconst envelope = { body: raw.toString(\"hex\"), bodyEncoding: \"hex\" };\n// after\nconst envelope = { body: raw.toString(\"base64\"), bodyEncoding: \"base64\" };","handlingStrategy":"type-guard","validationCode":"const ALLOWED_ENCODINGS = new Set([undefined, \"utf8\", \"base64\"]);\nfunction hasSupportedEncoding(envelope) {\n  return ALLOWED_ENCODINGS.has(envelope?.bodyEncoding);\n}\nif (!hasSupportedEncoding(envelope)) throw new Error(`Unsupported bodyEncoding: ${envelope.bodyEncoding}`);","typeGuard":"function hasKnownEncoding(en: unknown): en is { body: string; bodyEncoding?: \"utf8\" | \"base64\" } {\n  const e = en as { bodyEncoding?: unknown };\n  return typeof en === \"object\" && en !== null &&\n    (e.bodyEncoding === undefined || e.bodyEncoding === \"utf8\" || e.bodyEncoding === \"base64\");\n}","tryCatchPattern":"try {\n  const bytes = decodeSandboxBridgeBody(envelope, maxBodyBytes);\n} catch (err) {\n  if (err instanceof Error && err.message === \"Unsupported bridge body encoding.\") {\n    throw new Error(`bodyEncoding '${envelope?.bodyEncoding}' not supported; use utf8 or base64`);\n  } else throw err;\n}","preventionTips":["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."],"tags":["nodejs","encoding","validation","sandbox-bridge"],"backgroundTag":"unsupported-enum-value","analyzedSha":"3f1d897a7c018d76563a21c6e39c3c9b03933622","analyzedAt":"2026-09-18T08:03:59.046Z","contentChangedAt":"2026-09-18T08:03:59.046Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}