denoland/deno · error · TypeError

buffer must be a TypedArray or a DataView

Error message

buffer must be a TypedArray or a DataView

What it means

v8.deserialize(buffer) expects the serialized value's backing bytes as a TypedArray or DataView. The polyfill checks isArrayBufferView(buffer) and throws a plain TypeError otherwise, matching Node. A bare ArrayBuffer, a string, or null all fail because the deserializer needs the view's byteOffset and length.

Source

Thrown at ext/node/polyfills/v8.ts:318

    if (count === 0) return [];
    return [`${count} instance(s) of ${name}`];
  }
  // Default format returns live object handles, which would require V8's
  // `HeapProfiler::QueryObjects` (not exposed in rusty_v8). Returning an
  // empty array keeps the signature sensible.
  return [];
}

// deno-lint-ignore no-explicit-any
function serialize(value: any) {
  const ser = new DefaultSerializer();
  ser.writeHeader();
  ser.writeValue(value);
  return ser.releaseBuffer();
}
function deserialize(buffer: Buffer | ArrayBufferView | DataView) {
  if (!isArrayBufferView(buffer)) {
    throw new TypeError(
      "buffer must be a TypedArray or a DataView",
    );
  }
  const der = new DefaultDeserializer(buffer);
  der.readHeader();
  return der.readValue();
}

const kHandle = Symbol("kHandle");
const kHeaderWritten = Symbol("kHeaderWritten");

class Serializer {
  [kHandle]: object;
  [kHeaderWritten] = false;
  constructor() {
    this[kHandle] = op_v8_new_serializer(this);
  }

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Wrap the buffer in a view: v8.deserialize(new Uint8Array(arrayBuffer)).
  2. Use Buffer.from(data) (or Buffer.concat(chunks)) for network/file payloads before deserializing.
  3. Type the parameter as Buffer | ArrayBufferView | DataView in your API so mistakes surface at compile time.

Example fix

// before
const ab = await response.arrayBuffer(); // bare ArrayBuffer
const value = v8.deserialize(ab);        // TypeError

// after
const value = v8.deserialize(new Uint8Array(await response.arrayBuffer()));
Defensive patterns

Strategy: type-guard

Validate before calling

function asView(buf) {
  return ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf);
}
// then always: v8.deserialize(asView(data))

Type guard

const isBufferView = (v) => ArrayBuffer.isView(v);

Prevention

When it happens

Trigger: v8.deserialize(new ArrayBuffer(n)), v8.deserialize(someString), or v8.deserialize(null). A Node Buffer or any TypedArray/DataView passes.

Common situations: Storing v8.serialize() output and then transferring/postMessaging it so it arrives as a bare ArrayBuffer; reading a file or fetch body into an ArrayBuffer and forgetting to wrap; structured-clone round trips that strip the view.

Related errors


AI-assisted analysis of denoland/deno@9ad36f7a2c (2026-08-20). Data as JSON: /api/errors/5474b6d5cf42686c. Report an issue: GitHub.