denoland/deno · error · TypeError

Expected ArrayBuffer or ArrayBufferView for write chunk

Error message

Expected ArrayBuffer or ArrayBufferView for write chunk

What it means

Resource-backed WritableStreams (Deno.stdout/stderr .writable, file .writable, connection writables) coerce every chunk with bufferSourceAsUint8Array inside their write() sink (ext/web/06_streams.js:1524-1527 -> 441-462). Only TypedArrays, DataView, and (Shared)ArrayBuffers are accepted; a string, number, Blob, or plain object throws TypeError 'Expected ArrayBuffer or ArrayBufferView for write chunk', rejecting the writer.write() promise. Generic WritableStreams accept any chunk — this guard is specific to rid-backed byte streams.

Source

Thrown at ext/web/06_streams.js:459

function bufferSourceAsUint8Array(O) {
  if (isTypedArray(O)) {
    return new Uint8Array(
      TypedArrayPrototypeGetBuffer(/** @type {Uint8Array} */ (O)),
      TypedArrayPrototypeGetByteOffset(/** @type {Uint8Array} */ (O)),
      TypedArrayPrototypeGetByteLength(/** @type {Uint8Array} */ (O)),
    );
  }
  if (ArrayBufferIsView(O)) {
    return new Uint8Array(
      DataViewPrototypeGetBuffer(/** @type {DataView} */ (O)),
      DataViewPrototypeGetByteOffset(/** @type {DataView} */ (O)),
      DataViewPrototypeGetByteLength(/** @type {DataView} */ (O)),
    );
  }
  if (isAnyArrayBuffer(O)) {
    return new Uint8Array(/** @type {ArrayBuffer} */ (O));
  }
  throw new TypeError(
    "Expected ArrayBuffer or ArrayBufferView for write chunk",
  );
}

/**
 * Byte length of an ArrayBuffer or ArrayBufferView. Throws TypeError otherwise.
 * @param {unknown} O
 * @returns {number}
 */
function bufferSourceByteLength(O) {
  if (isTypedArray(O)) {
    return TypedArrayPrototypeGetByteLength(/** @type {Uint8Array} */ (O));
  }
  if (ArrayBufferIsView(O)) {
    return DataViewPrototypeGetByteLength(/** @type {DataView} */ (O));
  }
  if (isAnyArrayBuffer(O)) {
    return ArrayBufferPrototypeGetByteLength(/** @type {ArrayBuffer} */ (O));

View on GitHub (pinned to 9ad36f7a2c)

Solutions

  1. Encode text chunks before writing: writer.write(new TextEncoder().encode(text)).
  2. Convert Blobs first: writer.write(new Uint8Array(await blob.arrayBuffer())).
  3. Pipe string producers through a TextEncoderStream so the byte stream receives Uint8Array chunks.
  4. Type stream chunks as Uint8Array at the boundary to catch regressions at compile time.

Example fix

// before
const w = Deno.stdout.writable.getWriter();
await w.write('hello\n'); // TypeError: Expected ArrayBuffer or ArrayBufferView for write chunk

// after
const encoder = new TextEncoder();
await w.write(encoder.encode('hello\n'));
Defensive patterns

Strategy: type-guard

Validate before calling

const toChunk = (d) =>
  typeof d === 'string' ? new TextEncoder().encode(d) : d;
const chunk = toChunk(data);
if (chunk instanceof ArrayBuffer || ArrayBuffer.isView(chunk)) {
  await writer.write(chunk);
} else {
  throw new TypeError(`unsupported chunk type: ${typeof chunk}`);
}

Type guard

function isBufferSource(v) {
  return v instanceof ArrayBuffer || ArrayBuffer.isView(v);
}

Try / catch

try {
  await writer.write(chunk);
} catch (e) {
  if (e instanceof TypeError && e.message.includes('write chunk')) {
    await writer.write(new TextEncoder().encode(chunk));
  } else throw e;
}

Prevention

When it happens

Trigger: await Deno.stdout.writable.getWriter().write('hello'); writing a Blob or plain object chunk to file.writable or a connection's writable; code ported from Node streams that writes strings with an assumed encoding.

Common situations: Logging pipelines writing formatted strings directly to stdout/stderr writables; saving JSON.stringify output to a file stream; feeding fetch/socket bodies with strings or Blobs; refactors where a transform upstream silently changes chunk type from bytes to text.

Related errors


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