evanw/esbuild · error · Error

The input to "transform" must be a string or a Uint8Array

Error message

The input to "transform" must be a string or a Uint8Array

What it means

transform() only accepts source code as a string or a Uint8Array; anything else is rejected up front at lib/shared/common.ts:710 before options are even parsed. This is a hard precondition because the input is sent to the binary as bytes.

Solutions

  1. Ensure the first argument is a string or Uint8Array (read file contents first with fs.readFileSync if needed).
  2. If you have a path, use build({ entryPoints: [path] }) instead of transform().
  3. Add a type guard before calling to surface a clearer error in your own code.

Example fix

// before
const code = fs.readFile('app.ts') // forgot await/callback -> undefined
await esbuild.transform(code, { loader: 'ts' })

// after
const code = await fs.promises.readFile('app.ts', 'utf8')
await esbuild.transform(code, { loader: 'ts' })
Defensive patterns

Strategy: type-guard

Validate before calling

function ensureTransformInput(input) {
  if (typeof input !== 'string' && !(input instanceof Uint8Array)) {
    throw new TypeError('transform input must be a string or Uint8Array')
  }
  return input
}
await esbuild.transform(ensureTransformInput(maybeCode), { loader: 'ts' })

Type guard

function isTransformInput(v): v is string | Uint8Array {
  return typeof v === 'string' || v instanceof Uint8Array
}
if (!isTransformInput(input)) throw new TypeError('invalid transform input')

Prevention

When it happens

Trigger: Calling `transform(null)`, `transform(undefined)`, `transform(123)`, `transform({ code: '...' })`, `transform(Buffer?)` in an environment where the value is not a string/Uint8Array, or forgetting to read a file's contents before transforming.

Common situations: Passing an options object as the first argument by mistake; passing a path string expecting esbuild to read the file (use build() for that); async code that resolved to undefined; receiving data from an API that returned JSON instead of text.

Related errors


AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09). Data as JSON: /api/errors/4f65b072257b6cfa. Report an issue: GitHub.

Appendix: source

Thrown at lib/shared/common.ts:710

    // Ideally the "transform()" API would be faster than calling "build()"
    // since it doesn't need to touch the file system. However, performance
    // measurements with large files on macOS indicate that sending the data
    // over the stdio pipe can be 2x slower than just using a temporary file.
    //
    // This appears to be an OS limitation. Both the JavaScript and Go code
    // are using large buffers but the pipe only writes data in 8kb chunks.
    // An investigation seems to indicate that this number is hard-coded into
    // the OS source code. Presumably files are faster because the OS uses
    // a larger chunk size, or maybe even reads everything in one syscall.
    //
    // The cross-over size where this starts to be faster is around 1mb on
    // my machine. In that case, this code tries to use a temporary file if
    // possible but falls back to sending the data over the stdio pipe if
    // that doesn't work.
    let start = (inputPath: string | null) => {
      try {
        if (typeof input !== 'string' && !(input instanceof Uint8Array))
          throw new Error('The input to "transform" must be a string or a Uint8Array')
        let {
          flags,
          mangleCache,
        } = flagsForTransformOptions(callName, options, isTTY, transformLogLevelDefault)
        let request: protocol.TransformRequest = {
          command: 'transform',
          flags,
          inputFS: inputPath !== null,
          input: inputPath !== null ? protocol.encodeUTF8(inputPath)
            : typeof input === 'string' ? protocol.encodeUTF8(input)
              : input,
        }
        if (mangleCache) request.mangleCache = mangleCache
        sendRequest<protocol.TransformRequest, protocol.TransformResponse>(refs, request, (error, response) => {
          if (error) return callback(new Error(error), null)
          let errors = replaceDetailsInMessages(response!.errors, details)
          let warnings = replaceDetailsInMessages(response!.warnings, details)
          let outstanding = 1

View on GitHub (pinned to f6058f8364)