hcengineering/platform · error · TypeError

Unsupported data type

Error message

Unsupported data type

What it means

TypeError thrown by the internal toBuffer helper when the data argument is neither a Buffer, a string, nor a Node Readable stream. The datalake client only accepts these three types for upload bodies; anything else (Uint8Array, Blob, web ReadableStream, plain object, undefined) reaches the else branch.

Source

Thrown at foundations/server/packages/datalake/src/client.ts:495

      ctx.error('failed to abort multipart upload', { workspace, objectName, err })
      throw new DatalakeError('Failed to abort multipart upload')
    }
  }
}

async function toBuffer (data: Buffer | string | Readable): Promise<Buffer> {
  if (Buffer.isBuffer(data)) {
    return data
  } else if (typeof data === 'string') {
    return Buffer.from(data)
  } else if (data instanceof Readable) {
    const chunks: Buffer[] = []
    for await (const chunk of data) {
      chunks.push(chunk)
    }
    return Buffer.concat(chunks as any)
  } else {
    throw new TypeError('Unsupported data type')
  }
}

async function * getChunks (data: Buffer | string | Readable, chunkSize: number): AsyncGenerator<Buffer> {
  if (Buffer.isBuffer(data)) {
    let offset = 0
    while (offset < data.length) {
      yield data.subarray(offset, offset + chunkSize)
      offset += chunkSize
    }
  } else if (typeof data === 'string') {
    const buffer = Buffer.from(data)
    yield * getChunks(buffer, chunkSize)
  } else if (data instanceof Readable) {
    let buffer = Buffer.alloc(0)

    for await (const chunk of data) {
      buffer = Buffer.concat([buffer, chunk])

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Convert typed arrays before calling: Buffer.from(uint8array).
  2. Wrap web streams with Readable.fromWeb(stream) from 'node:stream'.
  3. Enforce the Buffer | string | Readable union in TypeScript and remove `as any` casts.
  4. Log the value's constructor name to confirm what was actually passed.

Example fix

// before
await client.put(ctx, ws, name, encoder.encode('hello')) // Uint8Array
// after
await client.put(ctx, ws, name, Buffer.from(encoder.encode('hello')))
Defensive patterns

Strategy: validation

Validate before calling

function toUploadBody(data: unknown): Buffer {
  if (Buffer.isBuffer(data)) return data
  if (typeof data === 'string') return Buffer.from(data)
  if (data instanceof Uint8Array) return Buffer.from(data)
  if (data instanceof Readable) return null as never // handle streams separately
  throw new TypeError(`Expected Buffer|string|Readable, got ${Object.prototype.toString.call(data)}`)
}

Type guard

const isSupportedBody = (d: unknown): d is Buffer | string | Readable =>
  Buffer.isBuffer(d) || typeof d === 'string' || d instanceof Readable

Try / catch

try {
  await client.put(ctx, ws, name, body)
} catch (err) {
  if (err instanceof TypeError && err.message.includes('Unsupported data type')) {
    console.error('Convert the body to Buffer/string/Readable before uploading')
  }
  throw err
}

Prevention

When it happens

Trigger: Passing an unsupported value as the body to a client upload path that calls toBuffer: e.g. a Uint8Array from TextEncoder/crypto, a Blob/File from web APIs, a JSON object, or undefined because the variable was never assigned.

Common situations: Code assuming fetch-style BodyInit acceptance (Uint8Array/Blob); TypeScript unions widened with `as any`; using an API that returns a web ReadableStream instead of a Node Readable.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/5e7b4b5dc6f66052. Report an issue: GitHub.