tursodatabase/turso · error · Error
panic: MainWorker is not initialized
Error message
panic: MainWorker is not initialized
What it means
The bundle-variant WASM promise entry (promise-bundle.ts:8) defines init(): it awaits initThreadPool() and then requires the live-exported MainWorker from index-bundle.js to be non-null. MainWorker is assigned inside the setupMainThread callback in index-bundle.ts when the worker is created; if it is still null after initThreadPool(), the worker was never registered in this module instance. The classic cause is the bundler creating two copies of the wasm module (only the copy that ran setupMainThread got the worker) or picking an entry variant your bundler does not support.
Source
Thrown at bindings/javascript/packages/wasm/promise-bundle.ts:8
import { DatabasePromise, DatabaseOpts, SqliteError, Transaction } from "@tursodatabase/database-common"
import { registerFileAtWorker, unregisterFileAtWorker, ioNotifier } from "@tursodatabase/database-wasm-common";
import { initThreadPool, MainWorker, Database as NativeDatabase } from "./index-bundle.js";
async function init(): Promise<Worker> {
await initThreadPool();
if (MainWorker == null) {
throw new Error("panic: MainWorker is not initialized");
}
return MainWorker;
}
class Database extends DatabasePromise {
#worker: Worker | null;
constructor(path: string, opts: DatabaseOpts = {}) {
super(
new NativeDatabase(path, opts) as unknown as any,
() => ioNotifier.waitForCompletion(),
)
}
/**
* connect database and pre-open necessary files in the OPFS
*/
override async connect() {
if (!this.memory) {
const worker = await init();View on GitHub (pinned to 244cde92a7)
Solutions
- Import Database and everything else from exactly one entry point of one package copy (dedupe @tursodatabase/database-wasm in the lockfile).
- Call and await the entry's init() once at startup before constructing any Database.
- Pick the entry variant matching your bundler (e.g. promise-vite-dev-hack under Vite dev, promise-turbopack-hack under Turbopack) instead of mixing them.
- Ensure the worker and turso.wasm assets are served (check network tab) so setupMainThread can create the worker.
- Keep the module out of SSR main builds (load it lazily in the browser only).
Example fix
// before
import { Database } from "@tursodatabase/database-wasm/promise-bundle";
const db = new Database("app.db"); // module copy never initialized MainWorker
// after
import { init, Database } from "@tursodatabase/database-wasm/promise-bundle";
await init(); // worker registered in THIS module instance
const db = new Database("app.db"); Defensive patterns
Strategy: validation
Validate before calling
import { init, Database } from "@tursodatabase/database-wasm/promise-bundle";
let ready: Promise<Worker> | null = null;
export function ensureInit() {
return (ready ??= init()); // single, awaited initialization
}
// app startup: await ensureInit(); before any new Database(...) Try / catch
try {
await init();
} catch (e) {
if (e instanceof Error && /MainWorker is not initialized/.test(e.message)) {
// module duplication or failed worker spawn: dedupe entries / check network for worker.js + turso.wasm
} else throw e;
} Prevention
- Import Database from exactly one entry variant of one package copy.
- Await init() once at startup; cache the promise.
- Verify worker.js and turso.wasm assets load (network tab) after bundling.
- Keep the module out of SSR builds; load it lazily in the browser.
When it happens
Trigger: Importing the database from one module instance while another duplicate copy (created by bundler resolution) ran setupMainThread; mixing entry files (index-bundle.js, index-default.js, hack variants) in one app; calling Database before the module's top-level await (fetch of turso.wasm + setupMainThread) completed in the copy you imported; worker script failing to load so the callback never assigned MainWorker.
Common situations: Webpack/rollup-style setups where '#index' or subpath imports resolve to two physical files; monorepos with duplicate @tursodatabase/database-wasm versions; SSR frameworks evaluating the module on the server where Worker is unavailable; using the bundle variant with a bundler that needs the vite/turbopack hack variant instead.
Related errors
- panic: MainWorker is not initialized
- panic: MainWorker is not initialized
- panic: MainWorker is not initialized
- method ${name} must be invoked only from the worker thread
- method ${name} must be invoked only from the main thread
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/34ae6d7da32a8e28.
Report an issue: GitHub.