{"id":"b277a36e068d155d","repo":"evanw/esbuild","slug":"the-write-option-is-unavailable-in-this-environm","errorCode":null,"errorMessage":"The \"write\" option is unavailable in this environment","messagePattern":"The \"write\" option is unavailable in this environment","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/shared/common.ts","lineNumber":923,"sourceCode":"  } catch (e) {\n    handleError(e, '')\n  }\n\n  // \"buildOrContext\" cannot be written using async/await due to \"buildSync\"\n  // and must be written in continuation-passing style instead\n  function buildOrContextContinue(requestPlugins: protocol.BuildPlugin[] | null, runOnEndCallbacks: RunOnEndCallbacks, scheduleOnDisposeCallbacks: () => void) {\n    const writeDefault = streamIn.hasFS\n    const {\n      entries,\n      flags,\n      write,\n      stdinContents,\n      stdinResolveDir,\n      absWorkingDir,\n      nodePaths,\n      mangleCache,\n    } = flagsForBuildOptions(callName, options, isTTY, buildLogLevelDefault, writeDefault)\n    if (write && !streamIn.hasFS) throw new Error(`The \"write\" option is unavailable in this environment`)\n\n    // Construct the request\n    const request: protocol.BuildRequest = {\n      command: 'build',\n      key: buildKey,\n      entries,\n      flags,\n      write,\n      stdinContents,\n      stdinResolveDir,\n      absWorkingDir: absWorkingDir || defaultWD,\n      nodePaths,\n      context: isContext,\n    }\n    if (requestPlugins) request.plugins = requestPlugins\n    if (mangleCache) request.mangleCache = mangleCache\n\n    // Factor out response handling so it can be reused for rebuilds","sourceCodeStart":905,"sourceCodeEnd":941,"githubUrl":"https://github.com/evanw/esbuild/blob/6ff1d8b0d8c134e867a397eef39702a223ebef9e/lib/shared/common.ts#L905-L941","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (browser / wasm)\nawait esbuild.build({ entryPoints: ['app.ts'], bundle: true, write: true });\n// after\nconst result = await esbuild.build({ entryPoints: ['app.ts'], bundle: true, write: false });\nfor (const f of result.outputFiles) console.log(f.path, f.text);","handlingStrategy":"type-guard","validationCode":"import { build } from 'esbuild';\n\n// Heuristic: only set write:true when we know we have a filesystem.\nconst hasFS = typeof process !== 'undefined' && !!process.versions?.node;\nawait build({ ...opts, write: hasFS ? true : false });","typeGuard":"function supportsWrite(): boolean {\n  // The wasm/browser entry sets hasFS:false internally; approximate at call site.\n  return typeof process !== 'undefined' && typeof process.versions?.node === 'string'\n    && typeof require === 'function';\n}","tryCatchPattern":"try {\n  await esbuild.build({ ...opts, write: true });\n} catch (e) {\n  if (/\"write\" option is unavailable/.test(e.message)) {\n    // fallback: read output in-memory\n    const res = await esbuild.build({ ...opts, write: false });\n    handleOutputFiles(res.outputFiles);\n  } else throw e;\n}","preventionTips":["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."],"tags":["environment","filesystem","wasm","browser"],"analyzedSha":"6ff1d8b0d8c134e867a397eef39702a223ebef9e","analyzedAt":"2026-08-03T19:42:38.433Z","schemaVersion":2}