{"record":{"id":"b9c088abec8f34d7","repo":"tursodatabase/turso","slug":"panic-mainworker-is-not-initialized-b9c088","errorCode":null,"errorMessage":"panic: MainWorker is not initialized","messagePattern":"panic: MainWorker is not initialized","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"bindings/javascript/packages/wasm/promise-default.ts","lineNumber":8,"sourceCode":"import { DatabasePromise, DatabaseOpts, SqliteError, Transaction } from \"@tursodatabase/database-common\"\nimport { registerFileAtWorker, unregisterFileAtWorker, ioNotifier } from \"@tursodatabase/database-wasm-common\";\nimport { initThreadPool, MainWorker, Database as NativeDatabase } from \"./index-default.js\";\n\nasync function init(): Promise<Worker> {\n    await initThreadPool();\n    if (MainWorker == null) {\n        throw new Error(\"panic: MainWorker is not initialized\");\n    }\n    return MainWorker;\n}\n\nclass Database extends DatabasePromise {\n    #worker: Worker | null;\n    constructor(path: string, opts: DatabaseOpts = {}) {\n        const nativeDb = new NativeDatabase(path, opts);\n        super(\n            nativeDb as unknown as any,\n            // In-memory databases use MemoryIO which completes I/O synchronously,\n            // so there's no OPFS Worker dispatch and the IONotifier would never fire.\n            // Use undefined (defaults to no-op) so the step loop retries immediately.\n            (nativeDb as any).memory ? undefined : () => ioNotifier.waitForCompletion(),\n        )\n    }\n    /**\n     * connect database and pre-open necessary files in the OPFS","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/tursodatabase/turso/blob/244cde92a7df7f9b8b8b7a4075c35a12977e303e/bindings/javascript/packages/wasm/promise-default.ts#L1-L26","documentation":"The default WASM promise entry (promise-default.ts:8) throws this from init() when MainWorker - a live export of index-default.ts assigned inside the setupMainThread callback - is still null after initThreadPool() resolves. index-default.ts uses top-level await (fetches turso.wasm, then setupMainThread spawns the 'turso-database' module worker), so a null MainWorker means the worker-creation callback never ran for the module instance you imported: either a duplicate module copy, an unloaded worker/wasm asset, or calling into the module before its top-level await chain finished.","triggerScenarios":"Bundler resolving @tursodatabase/database-wasm/promise-default and other deep imports to different physical copies of index-default.js; the browser failing to fetch ./turso.wasm32-wasi.wasm or ./worker.js (404 from wrong base path after bundling); constructing Database in a module that captured the exports before the top-level await settled; running under SSR/jsdom where Worker is missing so setupMainThread silently never assigned MainWorker.","commonSituations":"Vite/Next.js dev servers re-optimizing and serving two copies of the wasm package; assets not copied to the dist base path; Node SSR prerender importing the browser entry; ad-blockers or CSP blocking worker creation.","solutions":["Await init() from the same entry module before any Database construction.","Verify turso.wasm32-wasi.wasm and worker.js are fetched successfully (network tab) and match the import base.","Dedupe the package so a single index-default.js instance exists (check the bundler's module graph / lockfile duplicates).","Load the wasm entry lazily and only in the browser (dynamic import inside useEffect/onMount), never during SSR."],"exampleFix":"// before\nimport { Database } from \"@tursodatabase/database-wasm/promise-default\";\nexport const db = new Database(\"app.db\"); // module-level, init not awaited\n\n// after\nimport { init, Database } from \"@tursodatabase/database-wasm/promise-default\";\nexport async function openDb() {\n  await init();\n  return new Database(\"app.db\");\n}","handlingStrategy":"validation","validationCode":"import { init, Database } from \"@tursodatabase/database-wasm/promise-default\";\nexport async function openDb(path: string) {\n  await init(); // resolves only after MainWorker exists\n  return new Database(path);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await init();\n} catch (e) {\n  if (e instanceof Error && /MainWorker is not initialized/.test(e.message)) {\n    // check for duplicate module copies and 404s on turso.wasm32-wasi.wasm / worker.js\n  } else throw e;\n}","preventionTips":["Never construct Database at module top level; await init() first.","Dedupe @tursodatabase/database-wasm so index-default.js exists once.","Confirm wasm/worker assets are served from the correct base path.","Dynamic-import the entry inside browser-only effects (no SSR)."],"tags":["wasm","initialization","worker","module-loading","top-level-await"],"backgroundTag":"module-not-initialized","analyzedSha":"244cde92a7df7f9b8b8b7a4075c35a12977e303e","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}