{"record":{"id":"d35f382f50a50be2","repo":"schollz/croc","slug":"message-is-too-large-payload-bytelength-bytes","errorCode":null,"errorMessage":"Message is too large (${payload.byteLength} bytes)","messagePattern":"Message is too large \\((.+?) bytes\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/protocol/framing.ts","lineNumber":8,"sourceCode":"import { concatBytes } from \"./bytes\";\n\nexport const MAX_FRAME_SIZE = 64 * 1024 * 1024;\nconst MAGIC = new Uint8Array([0x63, 0x72, 0x6f, 0x63]);\n\nexport function encodeFrame(payload: Uint8Array) {\n  if (payload.byteLength > MAX_FRAME_SIZE) {\n    throw new Error(`Message is too large (${payload.byteLength} bytes)`);\n  }\n  const frame = new Uint8Array(8 + payload.byteLength);\n  frame.set(MAGIC, 0);\n  new DataView(frame.buffer).setUint32(4, payload.byteLength, true);\n  frame.set(payload, 8);\n  return frame;\n}\n\nexport class FrameDecoder {\n  private buffer = new Uint8Array();\n\n  push(chunk: Uint8Array) {\n    this.buffer =\n      this.buffer.byteLength === 0 ? chunk.slice() : concatBytes(this.buffer, chunk);\n    const messages: Uint8Array[] = [];\n\n    while (this.buffer.byteLength >= 8) {\n      for (let index = 0; index < MAGIC.byteLength; index += 1) {","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/framing.ts#L1-L26","documentation":"encodeFrame() wraps a payload in croc framing (4-byte magic 'croc' + little-endian uint32 length + payload) and refuses payloads larger than MAX_FRAME_SIZE (64 MiB). The length field is uint32, and the cap bounds memory use on both encode and decode; anything larger cannot be framed.","triggerScenarios":"Calling encodeFrame(payload) where payload.byteLength > 64 * 1024 * 1024. Typically caused by sending a single huge chunk, an un-split file block, or a bulk base64 blob through the relay instead of chunking at the application layer.","commonSituations":"Raising the application chunk size above 64 MiB; serializing a whole file's metadata plus data in one message; compressing already-incompressible data that still exceeds the cap; porting the Go croc client's larger frame limit without matching MAX_FRAME_SIZE.","solutions":["Split the payload into chunks of at most MAX_FRAME_SIZE and frame each chunk separately, reassembling on the receiver via FrameDecoder.","Check payload.byteLength before calling encodeFrame and fail with your own actionable error message.","If a larger cap is genuinely required in a controlled deployment, raise MAX_FRAME_SIZE on BOTH ends (encodeFrame and FrameDecoder share it) and keep it below 2^32.","Compress the payload first (the codec already supports wasm.compress) and re-check the size."],"exampleFix":"// before\nconst frame = encodeFrame(payload); // payload may be 100 MiB\n// after\nconst CHUNK = 8 * 1024 * 1024;\nfor (let off = 0; off < payload.byteLength; off += CHUNK) {\n  const frame = encodeFrame(payload.subarray(off, off + CHUNK));\n  send(frame);\n}","handlingStrategy":"validation","validationCode":"const MAX_FRAME_SIZE = 64 * 1024 * 1024;\nfunction assertFramable(payload: Uint8Array): void {\n  if (payload.byteLength > MAX_FRAME_SIZE) {\n    throw new RangeError(`payload ${payload.byteLength} exceeds frame cap; split into <=${MAX_FRAME_SIZE} chunks`);\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  send(encodeFrame(payload));\n} catch (error) {\n  if (error instanceof RangeError || /too large/.test(String(error))) {\n    await sendChunked(payload, 8 * 1024 * 1024); // fall back to chunked send\n    return;\n  }\n  throw error;\n}","preventionTips":["Chunk application payloads well below 64 MiB (8–16 MiB is typical) before framing.","Size-check payloads in your send helper so the failure surfaces with your own actionable message.","If raising the cap, change MAX_FRAME_SIZE identically on encode and decode sides and stay under 2^32."],"tags":["protocol","framing","size-limit","relay"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}