socketio/socket.io · error · Error

got plaintext data when reconstructing a packet

Error message

got plaintext data when reconstructing a packet

What it means

Thrown by the parser Decoder.add() when a plaintext (string) packet arrives while a BinaryReconstructor is already active. Once a BINARY_EVENT/BINARY_ACK packet has been received, the decoder expects only binary attachments until reconstruction completes; an intervening string frame breaks the stream protocol.

Source

Thrown at packages/socket.io-parser/lib/index.ts:185

      {
        reviver: undefined,
        maxAttachments: 10,
      },
      typeof opts === "function" ? { reviver: opts } : opts,
    );
  }

  /**
   * Decodes an encoded packet string into packet JSON.
   *
   * @param {String} obj - encoded packet
   */

  public add(obj: any) {
    let packet;
    if (typeof obj === "string") {
      if (this.reconstructor) {
        throw new Error("got plaintext data when reconstructing a packet");
      }
      packet = this.decodeString(obj);
      const isBinaryEvent = packet.type === PacketType.BINARY_EVENT;
      if (isBinaryEvent || packet.type === PacketType.BINARY_ACK) {
        packet.type = isBinaryEvent ? PacketType.EVENT : PacketType.ACK;
        // binary packet's json
        this.reconstructor = new BinaryReconstructor(packet);
      } else {
        // non-binary full packet
        super.emitReserved("decoded", packet);
      }
    } else if (isBinary(obj) || obj.base64) {
      // raw binary data
      if (!this.reconstructor) {
        throw new Error("got binary data when not reconstructing a packet");
      } else {
        packet = this.reconstructor.takeBinaryData(obj);
        if (packet) {

View on GitHub (pinned to ae7fb46e08)

Solutions

  1. Ensure the transport delivers frames in strict order: the BINARY_EVENT string packet followed by exactly its N binary attachments before any other string packet.
  2. If using a multiplexed/interleaved source, give each logical packet its own Decoder instance.
  3. Call decoder.destroy() to reset a stuck reconstructor before feeding fresh data.

Example fix

// before
decoder.add(binaryEventString);
// stray string arrives mid-reconstruction
decoder.add(anotherStringPacket); // throws

// after
decoder.add(binaryEventString);
// wait for all attachments; only then accept new string packets
decoder.add(buf1); decoder.add(buf2);
// reconstruction done, safe to feed next string packet
decoder.add(anotherStringPacket);
Defensive patterns

Strategy: validation

Validate before calling

function canAcceptString(decoder){ return !decoder.reconstructor; }

Type guard

function isReconstructing(decoder){ return !!decoder.reconstructor; }

Try / catch

try { decoder.add(str); }
catch(e){ if(/plaintext data when reconstructing/.test(e.message)){ decoder.destroy(); decoder.add(str);} else throw e; }

Prevention

When it happens

Trigger: The decoder receives a BINARY_EVENT packet (setting up a reconstructor) and then, before all declared attachments have arrived, receives another string-encoded packet via add().

Common situations: A buggy transport multiplexing frames out of order, a proxy/gateway that injects a ping or text frame into the stream, or a custom client that feeds interleaved string and binary data to the same Decoder instance.

Related errors


AI-assisted analysis of socketio/socket.io@ae7fb46e08 (2026-08-03). Data as JSON: /data/errors/e958ac69e6b163c4.json. Report an issue: GitHub.