{"record":{"id":"6f758e114d2bf844","repo":"schollz/croc","slug":"received-an-invalid-file-chunk","errorCode":null,"errorMessage":"Received an invalid file chunk","messagePattern":"Received an invalid file chunk","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/protocol/client.ts","lineNumber":586,"sourceCode":"        reject,\n      };\n    });\n  }\n\n  stop() {\n    this.stopped = true;\n    this.fail(new Error(\"Data receiver stopped\"));\n  }\n\n  private async read(socket: CrocSocket) {\n    const engine = wasm();\n    while (!this.stopped) {\n      try {\n        let payload = await engine.decrypt(await socket.receive(), this.key);\n        if (!this.noCompress) {\n          payload = await engine.decompress(payload, MAX_DECOMPRESSED_CHUNK_SIZE);\n        }\n        if (payload.byteLength < 9) throw new Error(\"Received an invalid file chunk\");\n        const positionBig = new DataView(\n          payload.buffer,\n          payload.byteOffset,\n          payload.byteLength,\n        ).getBigUint64(0, true);\n        if (positionBig > BigInt(Number.MAX_SAFE_INTEGER)) {\n          throw new Error(\"Received a file position that is too large\");\n        }\n        const position = Number(positionBig);\n        const bytes = payload.slice(8);\n        await this.accept(position, bytes);\n      } catch (error) {\n        if (this.stopped) return;\n        this.stopped = true;\n        this.fail(error instanceof Error ? error : new Error(String(error)));\n      }\n    }\n  }","sourceCodeStart":568,"sourceCodeEnd":604,"githubUrl":"https://github.com/schollz/croc/blob/e25f1bdc04f07f094d50b0a1bf67e2563944b57a/web/src/protocol/client.ts#L568-L604","documentation":"Thrown by DataReceiver.read when a decrypted (and decompressed) data payload is shorter than 9 bytes. Every valid data chunk is an 8-byte little-endian BigUint64 position prefix plus at least 1 byte of data, so anything smaller is a corrupt or non-conformant frame. This error fails the whole receiver because chunk integrity cannot be established.","triggerScenarios":"Decrypt succeeded but with a wrong key producing garbage plaintext that happens to be short; decompression of a corrupted payload yielding <9 bytes; sender implementation sends an empty or malformed chunk; socket fragmentation reassembly bug in the transport layer delivering a truncated frame.","commonSituations":"Key derivation mismatch between peers (different PAKE purpose/room inputs) so decryption yields garbage; WASM engine (compress/decompress) version skew between sender and recipient; a relay that truncates frames; memory corruption or slicing bugs in a custom CrocSocket implementation.","solutions":["Verify both peers run the same client build so wasm encrypt/decrypt/compress agree","Confirm the PAKE inputs (passphrase, room, purpose 'peer-transfer', curve) are identical on both sides — a mismatch usually fails decryption earlier, but partial garbage can land here","Inspect the transport layer for frame reassembly: log payload.byteLength per frame to find where truncation begins","Test with a known-good relay and small file to rule out network-path corruption"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Pre-flight: confirm both peers use the same engine build before transferring\n// (best-effort; integrity errors otherwise surface in DataReceiver)\nconst engine = wasm();\nif (typeof engine.compress !== \"function\" || typeof engine.decompress !== \"function\") {\n  throw new Error(\"WASM engine incomplete — rebuild the client\");\n}","typeGuard":null,"tryCatchPattern":"catch (e) {\n  if (e instanceof Error && e.message === \"Received an invalid file chunk\") {\n    // data-channel integrity lost: fail the transfer, suggest restart with fresh code phrase\n  }\n  throw e;\n}","preventionTips":["Ship sender and recipient from the same build so wasm encrypt/compress framing matches","Never change the chunk wire format (8-byte LE position + data) on one side only","On integrity errors, restart the whole transfer with a new code phrase instead of resuming"],"tags":["data-integrity","wasm","corruption","receiver"],"backgroundTag":null,"analyzedSha":"e25f1bdc04f07f094d50b0a1bf67e2563944b57a","analyzedAt":"2026-08-15T12:53:39.096Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}