evanw/esbuild · critical · Error

No UTF-8 codec found

Error message

No UTF-8 codec found

What it means

esbuild's stdio protocol layer needs to encode/decode UTF-8 between JS and the Go binary. lib/shared/stdio_protocol.ts:414-433 probes for TextEncoder/TextDecoder first (modern browsers and Node ≥12), then falls back to Buffer (Node 10), and if neither global is present, throws 'No UTF-8 codec found'. This is an environment-capability guard: the host JS runtime lacks both the Web TextCodec API and Node's Buffer, so esbuild cannot marshal strings.

Source

Thrown at lib/shared/stdio_protocol.ts:433

  let encoder = new TextEncoder()
  let decoder = new TextDecoder()
  encodeUTF8 = text => encoder.encode(text)
  decodeUTF8 = bytes => decoder.decode(bytes)
  encodeInvariant = 'new TextEncoder().encode("")'
}

// For node 10.x
else if (typeof Buffer !== 'undefined') {
  encodeUTF8 = text => Buffer.from(text)
  decodeUTF8 = bytes => {
    let { buffer, byteOffset, byteLength } = bytes
    return Buffer.from(buffer, byteOffset, byteLength).toString()
  }
  encodeInvariant = 'Buffer.from("")'
}

else {
  throw new Error('No UTF-8 codec found')
}

// Throw an error early if this isn't true. The test framework called "Jest"
// has some bugs regarding this edge case, and letting esbuild proceed further
// leads to confusing errors that make it seem like esbuild itself has a bug.
if (!(encodeUTF8('') instanceof Uint8Array))
  throw new Error(`Invariant violation: "${encodeInvariant} instanceof Uint8Array" is incorrectly false

This indicates that your JavaScript environment is broken. You cannot use
esbuild in this environment because esbuild relies on this invariant. This
is not a problem with esbuild. You need to fix your environment instead.
`)

export function readUInt32LE(buffer: Uint8Array, offset: number): number {
  return (
    buffer[offset++] |
    (buffer[offset++] << 8) |
    (buffer[offset++] << 16) |

View on GitHub (pinned to 6ff1d8b0d8)

Solutions

  1. Provide a TextEncoder/TextDecoder polyfill (e.g. 'fast-text-encoding', 'text-encoding') before importing esbuild.
  2. Run in a modern Node (≥12) or any current browser where TextEncoder is global.
  3. If you control the runtime, ensure the global TextEncoder constructor is defined on globalThis.

Example fix

// before — esbuild imported in an engine without TextEncoder
import * as esbuild from 'esbuild';
// throws: No UTF-8 codec found

// after — polyfill first
import 'fast-text-encoding';
import * as esbuild from 'esbuild';
Defensive patterns

Strategy: validation

Validate before calling

function ensureUtf8Codec() {
  if (typeof TextEncoder === 'undefined' && typeof Buffer === 'undefined') {
    throw new Error('This environment has no UTF-8 codec; import a TextEncoder polyfill before esbuild.');
  }
}
ensureUtf8Codec();
import 'esbuild';

Type guard

function hasUtf8Codec(): boolean {
  return typeof TextEncoder !== 'undefined' && typeof TextDecoder !== 'undefined'
    || typeof Buffer !== 'undefined';
}

Prevention

When it happens

Trigger: Running esbuild in a stripped-down JS engine that defines neither TextEncoder nor Buffer (some embedded JS runtimes, ancient browsers, or a polyfill-less environment). A bundler that tree-shook away a TextEncoder polyfill. Node started with --no-experimental-strip-types and a custom global setup that deleted Buffer.

Common situations: Edge/embedded JS engines (QuickJS, Hermes without textcodec polyfill). Older Internet Explorer without TextEncoder and without a Buffer shim. Test environments that sandbox globals.

Related errors


AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03). Data as JSON: /data/errors/83a8208a21485538.json. Report an issue: GitHub.