tursodatabase/turso · error · Error
panic: MainWorker is not initialized
Error message
panic: MainWorker is not initialized
What it means
The turbopack-hack variant (promise-turbopack-hack.ts:8) exists specifically to work around Turbopack's handling of the wasm/worker assets; init() awaits initThreadPool() and then asserts MainWorker (live export of index-turbopack-hack.js) is non-null. A null MainWorker means the setupMainThread callback in that module never created the worker - typically because Turbopack duplicated or mis-resolved the module, or the hack entry is being used under a bundler it was not meant for (or vice versa).
Source
Thrown at bindings/javascript/packages/wasm/promise-turbopack-hack.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-turbopack-hack.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
- Under Turbopack use the turbopack-hack entry consistently (and only it); under other bundlers use the matching variant.
- Await init() once at app startup before creating databases.
- Dedupe the package and confirm a single module instance serves all imports.
- If dev works but build fails (or vice versa), align the entry variant between dev and prod configs.
Example fix
// before
import { Database } from "@tursodatabase/database-wasm/promise-default"; // under Turbopack
// after
import { init, Database } from "@tursodatabase/database-wasm/promise-turbopack-hack";
await init(); Defensive patterns
Strategy: validation
Validate before calling
import { init, Database } from "@tursodatabase/database-wasm/promise-turbopack-hack";
await init();
const db = new Database("app.db"); Try / catch
try {
await init();
} catch (e) {
if (e instanceof Error && /MainWorker is not initialized/.test(e.message)) {
// wrong entry variant for this bundler, or duplicate module: align + dedupe
} else throw e;
} Prevention
- Use the turbopack-hack entry only under Turbopack, consistently in dev and prod.
- Await init() before any Database construction.
- Dedupe the package in monorepos to avoid split module instances.
When it happens
Trigger: Using the turbopack-hack entry under webpack/Vite (or the default entry under Turbopack), producing a module graph where the instance you import never ran setupMainThread's worker callback; Next.js dev (Turbopack) vs production (webpack) resolving different copies; worker.js/wasm assets missing from the Turbopack build output.
Common situations: Next.js apps that work in `next dev` (Turbopack) but throw at build time, or the reverse; entry-point churn during upgrades leaving imports split across variants; monorepo setups pulling two copies of the wasm package.
Related errors
- panic: MainWorker is not initialized
- panic: MainWorker is not initialized
- panic: MainWorker is not initialized
- sync is disabled as database was opened without sync support
- method ${name} must be invoked only from the worker thread
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/9448bc4381c50450.
Report an issue: GitHub.