evanw/esbuild · error · Error
You need to wait for the promise returned from "initialize"
Error message
You need to wait for the promise returned from "initialize" to be resolved before calling this
What it means
In the browser build, `ensureServiceIsRunning()` (`lib/npm/browser.ts:67`) throws this when `initializePromise` is set but `longLivedService` is not yet assigned — i.e. you called `initialize()` (which kicked off wasm download/instantiation) but then invoked `build`/`transform`/etc. before `await initialize()` resolved. The service is created only after the worker boots and WebAssembly instantiates.
Source
Thrown at lib/npm/browser.ts:67
if (stopService) stopService()
return Promise.resolve()
}
interface Service {
build: typeof types.build
context: typeof types.context
transform: typeof types.transform
formatMessages: typeof types.formatMessages
analyzeMetafile: typeof types.analyzeMetafile
}
let initializePromise: Promise<void> | undefined
let stopService: (() => void) | undefined
let longLivedService: Service | undefined
let ensureServiceIsRunning = (): Service => {
if (longLivedService) return longLivedService
if (initializePromise) throw new Error('You need to wait for the promise returned from "initialize" to be resolved before calling this')
throw new Error('You need to call "initialize" before calling this')
}
export const initialize: typeof types.initialize = options => {
options = common.validateInitializeOptions(options || {})
let wasmURL = options.wasmURL
let wasmModule = options.wasmModule
let useWorker = options.worker !== false
if (!wasmURL && !wasmModule) throw new Error('Must provide either the "wasmURL" option or the "wasmModule" option')
if (initializePromise) throw new Error('Cannot call "initialize" more than once')
initializePromise = startRunningService(wasmURL || '', wasmModule, useWorker)
initializePromise.catch(() => {
// Let the caller try again if this fails
initializePromise = void 0
})
return initializePromise
}
View on GitHub (pinned to 6ff1d8b0d8)
Solutions
- Await the promise returned by `initialize` before any other esbuild call: `await esbuild.initialize({ wasmURL })`.
- Store the initialize promise and chain every subsequent call off it (e.g. `await initPromise; return esbuild.build(...)`).
- Lazy-create the service through a singleton that awaits initialize before exposing build/transform.
- Add a regression test that calls your entry function twice quickly to catch the race.
Example fix
// before
import * as esbuild from 'esbuild-wasm'
esbuild.initialize({ wasmURL: '/esbuild.wasm' })
esbuild.transform(ts, { loader: 'ts' }) // throws: not resolved yet
// after
await esbuild.initialize({ wasmURL: '/esbuild.wasm' })
const out = await esbuild.transform(ts, { loader: 'ts' }) Defensive patterns
Strategy: validation
Validate before calling
let ready: Promise<void> | undefined
export function ensureEsbuildReady() {
if (!ready) ready = esbuild.initialize({ wasmURL })
return ready
}
// Usage: await ensureEsbuildReady(); then call esbuild.build(...) Type guard
function isInitializeComplete(svc: typeof esbuild): boolean {
// No public flag exists; track via your own ready promise.
return !!ready && /* resolved */ readyThennableSettled
} Try / catch
try {
return await esbuild.build(opts)
} catch (e) {
if (/wait for the promise returned from "initialize"/.test((e as Error).message)) {
await ensureEsbuildReady()
return esbuild.build(opts)
}
throw e
} Prevention
- Always `await esbuild.initialize(...)` before any other esbuild call.
- Centralize initialization behind a singleton that returns the ready promise.
- Chain every API call off the same ready promise.
- Add a unit test that calls your entry point before initialize resolves.
When it happens
Trigger: Calling `esbuild.build(...)`, `transform`, `context`, `formatMessages`, or `analyzeMetafile` synchronously between `esbuild.initialize(opts)` and the moment the returned promise resolves. Commonly: forgetting to `await`, calling inside a `.then` chain that races, or fire-and-forget initialize.
Common situations: Top-level code that calls initialize then immediately uses esbuild; React useEffect that calls initialize and then a sibling effect calls transform; missing `await` due to no top-level await; misordering in a script that loads wasm over a slow network.
Related errors
- Must provide either the "wasmURL" option or the "wasmModule"
- The "buildSync" API only works in node
- The "transformSync" API only works in node
- The "formatMessagesSync" API only works in node
- The "analyzeMetafileSync" API only works in node
AI-assisted analysis of evanw/esbuild@6ff1d8b0d8 (2026-08-03).
Data as JSON: /data/errors/cb09308b25be5e3a.json.
Report an issue: GitHub.