vitejs/vite · error · Error

Failed to decode base64-encoded data URL, Buffer and atob ar

Error message

Failed to decode base64-encoded data URL, Buffer and atob are not supported

What it means

The wasm runtime helper (wasmHelper at packages/vite/src/node/plugins/wasm.ts:54) decodes a `data:` base64 wasm URL at runtime. It first tries Node's Buffer.from, then browser global atob; if neither exists it throws. This is glue code shipped into the built bundle, so the error fires in whatever runtime consumes the output (an unusual JS engine, a sandbox, or an older browser without atob).

Source

Thrown at packages/vite/src/node/plugins/wasm.ts:54

  ...wasmCompileOptions.builtins.map((name) => `wasm:${name}`),
  wasmCompileOptions.importedStringConstants,
])

const wasmHelper = async (opts = {}, url: string) => {
  let result
  if (url.startsWith('data:')) {
    const urlContent = url.replace(/^data:.*?base64,/, '')
    let bytes
    if (typeof Buffer === 'function' && typeof Buffer.from === 'function') {
      bytes = Buffer.from(urlContent, 'base64')
    } else if (typeof atob === 'function') {
      const binaryString = atob(urlContent)
      bytes = new Uint8Array(binaryString.length)
      for (let i = 0; i < binaryString.length; i++) {
        bytes[i] = binaryString.charCodeAt(i)
      }
    } else {
      throw new Error(
        'Failed to decode base64-encoded data URL, Buffer and atob are not supported',
      )
    }
    result = await WebAssembly.instantiate(bytes, opts, wasmCompileOptions)
  } else {
    result = await instantiateFromUrl(url, opts)
  }
  return result.instance
}

const wasmHelperCode = wasmHelper.toString()

const instantiateFromUrl = async (url: string, opts?: WebAssembly.Imports) => {
  // https://github.com/mdn/webassembly-examples/issues/5
  // WebAssembly.instantiateStreaming requires the server to provide the
  // correct MIME type for .wasm files, which unfortunately doesn't work for
  // a lot of static file servers, so we just work around it by getting the
  // raw buffer.

View on GitHub (pinned to 89620f09af)

Solutions

  1. Raise build.assetsInlineLimit below the size of the .wasm file so Vite emits it as a real file URL fetched via instantiateFromUrl/instantiateFromFile instead of a data: URL.
  2. Run the output in an environment that provides atob (browsers) or Buffer (Node) — add the appropriate polyfill if you control the runtime.
  3. Load the wasm yourself with WebAssembly.instantiateStreaming from a fetched file instead of relying on Vite's ?init helper.

Example fix

// before: wasm inlined as data URL, fails in minimal runtime
export default defineConfig({})

// after: keep wasm as a file asset so no base64 decode is needed
export default defineConfig({
  build: { assetsInlineLimit: 0 },
})
Defensive patterns

Strategy: validation

Validate before calling

function runtimeCanDecodeBase64(): boolean {
  return typeof Buffer === 'function' || typeof atob === 'function'
}
if (wasmIsInlinedAsDataUrl && !runtimeCanDecodeBase64()) {
  throw new Error('target runtime cannot decode inlined wasm; raise assetsInlineLimit')
}

Type guard

function hasBase64Decoder(): boolean {
  return typeof Buffer === 'function' || typeof atob === 'function'
}

Prevention

When it happens

Trigger: Inlining a small .wasm as a data: URL (asset inlining under assetsInlineLimit) and running the output in a JS environment that has neither Node's Buffer nor window.atob (e.g. QuickJS, a restricted Worker, an embedded JS engine, or IE/old Safari).

Common situations: Targeting obscure/edge runtimes with inlined wasm; SSR/edge workers that strip Node globals; very small wasm modules that get auto-inlined and then run in a minimal sandbox.

Related errors


AI-assisted analysis of vitejs/vite@89620f09af (2026-08-03). Data as JSON: /data/errors/2a330175fe51f01b.json. Report an issue: GitHub.