socketio/socket.io · error · Error

illegal attachments

Error message

illegal attachments

What it means

Thrown by reconstructPacket/_reconstructPacket in the parser's binary module when a placeholder object's num field is not a valid index into the buffers array (it is not a number, is negative, or is >= buffers.length). During binary packet reconstruction each {_placeholder:true,num:N} marker is replaced by buffers[N]; an out-of-range N means the buffers and placeholders are out of sync.

Source

Thrown at packages/socket.io-parser/lib/binary.ts:74

export function reconstructPacket(packet, buffers) {
  packet.data = _reconstructPacket(packet.data, buffers);
  delete packet.attachments; // no longer useful
  return packet;
}

function _reconstructPacket(data, buffers) {
  if (!data) return data;

  if (data && data._placeholder === true) {
    const isIndexValid =
      typeof data.num === "number" &&
      data.num >= 0 &&
      data.num < buffers.length;
    if (isIndexValid) {
      return buffers[data.num]; // appropriate buffer (should be natural order anyway)
    } else {
      throw new Error("illegal attachments");
    }
  } else if (Array.isArray(data)) {
    for (let i = 0; i < data.length; i++) {
      data[i] = _reconstructPacket(data[i], buffers);
    }
  } else if (typeof data === "object") {
    for (const key in data) {
      if (Object.prototype.hasOwnProperty.call(data, key)) {
        data[key] = _reconstructPacket(data[key], buffers);
      }
    }
  }

  return data;
}

View on GitHub (pinned to ae7fb46e08)

Solutions

  1. Ensure the transport/adapter reliably delivers every binary attachment in order before reconstructPacket is called.
  2. If you construct packets manually, verify every {_placeholder:true,num} references a valid index (0 <= num < buffers.length).
  3. Upgrade encoder and decoder together so the placeholder/buffer contract matches.

Example fix

// before
const packet = reconstructPacket(rawPacket, partialBuffers); // throws if num out of range

// after
const expected = rawPacket.attachments || 0;
if (partialBuffers.length < expected) {
  throw new Error(`missing ${expected - partialBuffers.length} binary attachments`);
}
const packet = reconstructPacket(rawPacket, partialBuffers);
Defensive patterns

Strategy: validation

Validate before calling

function placeholdersOk(packet, buffers){
  let ok=true;
  (function walk(d){
    if(d && d._placeholder===true){ if(!(typeof d.num==='number'&&d.num>=0&&d.num<buffers.length)) ok=false; return; }
    if(Array.isArray(d)) d.forEach(walk); else if(d&&typeof d==='object') Object.keys(d).forEach(k=>walk(d[k]));
  })(packet.data);
  return ok;
}

Type guard

function hasAllAttachments(packet, buffers){
  return (packet.attachments||0) <= buffers.length;
}

Try / catch

if(!placeholdersOk(rawPacket, buffers)){ throw new Error('illegal attachments: missing buffers'); }
const packet = reconstructPacket(rawPacket, buffers);

Prevention

When it happens

Trigger: Reconstructing a binary packet whose placeholder references a buffer index that was never received, or where fewer binary attachments were supplied than the packet declared. Also triggered by hand-crafted/corrupted packets with bogus num values.

Common situations: A network/proxy dropping one of the binary attachment frames between the BINARY_EVENT header and the final buffer; a custom adapter that reorders or drops buffers; or a version mismatch between encoder and decoder that changes the placeholder format.

Related errors


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