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 rebuildsView on GitHub (pinned to 6ff1d8b0d8)
Solutions
- Omit 'write' so esbuild picks the environment-appropriate default, OR explicitly set write: false and read outputFiles from the result.
- 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.
- 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
- Default write to false in shared configs; only flip on under Node.
- Switch your import between 'esbuild' (node) and 'esbuild-wasm' (browser) deliberately, not accidentally.
- Document at the call site which environment the build runs in.
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
- Cannot use the "watch" API in this environment
- Cannot use the "serve" API in this environment
- Must provide either the "wasmURL" option or the "wasmModule"
- Failed to download ${JSON.stringify(wasm)}
- The "serve" API is not supported when using WebAssembly
AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03).
Data as JSON: /data/errors/b277a36e068d155d.json.
Report an issue: GitHub.