{"id":"f3ff1c4fae1949da","repo":"evanw/esbuild","slug":"the-wasmurl-option-only-works-in-the-browser","errorCode":null,"errorMessage":"The \"wasmURL\" option only works in the browser","messagePattern":"The \"wasmURL\" option only works in the browser","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/npm/node.ts","lineNumber":235,"sourceCode":"    refs: null,\n    metafile: typeof metafile === 'string' ? metafile : JSON.stringify(metafile),\n    options,\n    callback: (err, res) => { if (err) throw err; result = res! },\n  }))\n  return result!\n}\n\nexport const stop = () => {\n  if (stopService) stopService()\n  if (workerThreadService) workerThreadService.stop()\n  return Promise.resolve()\n}\n\nlet initializeWasCalled = false\n\nexport let initialize: typeof types.initialize = options => {\n  options = common.validateInitializeOptions(options || {})\n  if (options.wasmURL) throw new Error(`The \"wasmURL\" option only works in the browser`)\n  if (options.wasmModule) throw new Error(`The \"wasmModule\" option only works in the browser`)\n  if (options.worker) throw new Error(`The \"worker\" option only works in the browser`)\n  if (initializeWasCalled) throw new Error('Cannot call \"initialize\" more than once')\n  ensureServiceIsRunning()\n  initializeWasCalled = true\n  return Promise.resolve()\n}\n\ninterface Service {\n  build: typeof types.build\n  context: typeof types.context\n  transform: typeof types.transform\n  formatMessages: typeof types.formatMessages\n  analyzeMetafile: typeof types.analyzeMetafile\n}\n\nlet defaultWD = process.cwd()\nlet longLivedService: Service | undefined","sourceCodeStart":217,"sourceCodeEnd":253,"githubUrl":"https://github.com/evanw/esbuild/blob/6ff1d8b0d8c134e867a397eef39702a223ebef9e/lib/npm/node.ts#L217-L253","documentation":"The Node entry's `initialize` (`node.ts:235`) explicitly rejects the `wasmURL` option because Node uses the native binary and has no need to fetch wasm. The option is browser-only. Passing it means the code was written for the browser API but is running under the Node entry.","triggerScenarios":"Calling `esbuild.initialize({ wasmURL })` against the Node `esbuild` package (not `esbuild-wasm`). The check fires immediately during option validation.","commonSituations":"Copy-pasting browser example code into a Node script; sharing initialize code between a browser and Node entry without forking on environment; migrating from esbuild-wasm back to esbuild without removing the option.","solutions":["Drop the `wasmURL` option when using the `esbuild` package in Node — Node finds the native binary automatically.","If you genuinely need wasm in Node, use the `esbuild-wasm` package instead.","Gate initialize options on environment: build the options object conditionally based on `typeof window`."],"exampleFix":"// before (Node script)\nimport * as esbuild from 'esbuild'\nawait esbuild.initialize({ wasmURL: '/esbuild.wasm' }) // throws\n\n// after\nimport * as esbuild from 'esbuild'\n// no initialize needed; or:\nawait esbuild.initialize({})","handlingStrategy":"validation","validationCode":"function sanitizeNodeInitOpts(opts: Record<string, unknown>) {\n  delete opts.wasmURL\n  delete opts.wasmModule\n  return opts\n}","typeGuard":"function isBrowserInitOpts(o: unknown): boolean {\n  return !!o && typeof o === 'object' && ('wasmURL' in o || 'wasmModule' in o || 'worker' in o)\n}","tryCatchPattern":null,"preventionTips":["Don't pass browser-only options to the Node esbuild package.","Build the initialize options object per environment.","Use esbuild-wasm when you genuinely need wasm in any runtime.","Document which options are environment-specific in shared code."],"tags":["node","wasm","initialize","configuration","browser-only-option"],"analyzedSha":"6ff1d8b0d8c134e867a397eef39702a223ebef9e","analyzedAt":"2026-08-03T19:42:38.433Z","schemaVersion":2}