evanw/esbuild · error · Error

The "write" option is unavailable in this environment

Error message

The "write" option is unavailable in this environment

What it means

esbuild exposes a 'write' build option that, when true, tells the native Go binary to write output files directly to disk. In environments without a real filesystem (the browser WASM build, lib/npm/browser.ts:142 sets hasFS:false), the Go side cannot perform file I/O, so esbuild throws at lib/shared/common.ts:923 when 'write' is explicitly true while streamIn.hasFS is false. The default for write is derived from hasFS, so this only triggers when the caller forces write:true in a filesystem-less host.

Source

Thrown at lib/shared/common.ts:923

  } catch (e) {
    handleError(e, '')
  }

  // "buildOrContext" cannot be written using async/await due to "buildSync"
  // and must be written in continuation-passing style instead
  function buildOrContextContinue(requestPlugins: protocol.BuildPlugin[] | null, runOnEndCallbacks: RunOnEndCallbacks, scheduleOnDisposeCallbacks: () => void) {
    const writeDefault = streamIn.hasFS
    const {
      entries,
      flags,
      write,
      stdinContents,
      stdinResolveDir,
      absWorkingDir,
      nodePaths,
      mangleCache,
    } = flagsForBuildOptions(callName, options, isTTY, buildLogLevelDefault, writeDefault)
    if (write && !streamIn.hasFS) throw new Error(`The "write" option is unavailable in this environment`)

    // Construct the request
    const request: protocol.BuildRequest = {
      command: 'build',
      key: buildKey,
      entries,
      flags,
      write,
      stdinContents,
      stdinResolveDir,
      absWorkingDir: absWorkingDir || defaultWD,
      nodePaths,
      context: isContext,
    }
    if (requestPlugins) request.plugins = requestPlugins
    if (mangleCache) request.mangleCache = mangleCache

    // Factor out response handling so it can be reused for rebuilds

View on GitHub (pinned to 6ff1d8b0d8)

Solutions

  1. Omit 'write' so esbuild picks the environment-appropriate default, OR explicitly set write: false and read outputFiles from the result.
  2. If you need files written to disk, run the build under Node (lib/npm/node.ts hasFS:true) or Deno (lib/deno/mod.ts hasFS:true) instead of the browser/wasm build.
  3. Confirm you are importing the correct entry: 'esbuild' (node) vs 'esbuild-wasm' (browser) — the wasm entry cannot write.

Example fix

// before (browser / wasm)
await esbuild.build({ entryPoints: ['app.ts'], bundle: true, write: true });
// after
const result = await esbuild.build({ entryPoints: ['app.ts'], bundle: true, write: false });
for (const f of result.outputFiles) console.log(f.path, f.text);
Defensive patterns

Strategy: type-guard

Validate before calling

import { build } from 'esbuild';

// Heuristic: only set write:true when we know we have a filesystem.
const hasFS = typeof process !== 'undefined' && !!process.versions?.node;
await build({ ...opts, write: hasFS ? true : false });

Type guard

function supportsWrite(): boolean {
  // The wasm/browser entry sets hasFS:false internally; approximate at call site.
  return typeof process !== 'undefined' && typeof process.versions?.node === 'string'
    && typeof require === 'function';
}

Try / catch

try {
  await esbuild.build({ ...opts, write: true });
} catch (e) {
  if (/"write" option is unavailable/.test(e.message)) {
    // fallback: read output in-memory
    const res = await esbuild.build({ ...opts, write: false });
    handleOutputFiles(res.outputFiles);
  } else throw e;
}

Prevention

When it happens

Trigger: Using esbuild-wasm / @esbuild-wasm in the browser and passing build({ ..., write: true }). Importing esbuild from a sandboxed runtime (Cloudflare Workers, Deno Deploy edge, Deno with --no-check sandbox) that reports hasFS:false but the user sets write:true. Forcing write:true on the browser entrypoint of the npm package.

Common situations: Devs copy a Node build script (which writes to dist/) verbatim into a browser bundler playground or a Web Worker. Bundlers that tree-shake the node entry but the config still says write:true. Migrating from the native npm package to the wasm package without flipping write to false.

Related errors


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