tursodatabase/turso · error · Error

remoteWritesExperimental requires a non-null URL

Error message

remoteWritesExperimental requires a non-null URL

What it means

DatabaseOpts.url accepts either a plain string or a zero-argument function returning string | null, so callers can resolve the URL lazily (typically from an environment variable). resolveUrl() invokes that function and throws when it returns null, because remoteWritesExperimental needs a concrete remote endpoint to send writes to. A null resolution means configuration is incomplete, and the library fails fast at open time rather than at first write.

Source

Thrown at bindings/javascript/sync/packages/wasm/promise-vite-dev-hack.ts:45

        async write(path: string, data: Buffer | Uint8Array): Promise<void> {
            values.set(path, data);
        }
    }
};

async function init(): Promise<Worker> {
    await initThreadPool();
    if (MainWorker == null) {
        throw new Error("panic: MainWorker is not initialized");
    }
    return MainWorker;
}

function resolveUrl(url: string | (() => string | null)): string {
    if (typeof url === "function") {
        const resolved = url();
        if (resolved == null) {
            throw new Error("remoteWritesExperimental requires a non-null URL");
        }
        return resolved;
    }
    return url;
}

class Database extends DatabasePromise {
    #runner: Runner;
    #engine: any;
    #io: ProtocolIo;
    #guards: SyncEngineGuards;
    #worker: Worker | null;
    #remoteWriter: RemoteWriter | null = null;
    #db: any;
    constructor(opts: DatabaseOpts) {
        if (opts.url == null) {
            const db = new NativeDatabase(opts.path, { tracing: opts.tracing, experimental: opts.experimental }) as any;
            super(

View on GitHub (pinned to bad083fafb)

Solutions

  1. Set the environment variable the URL function reads (e.g. TURSO_DB_URL) in the environment where the database is opened
  2. Pass the URL as a plain string when it is known at build/startup time
  3. Make the function total: `url: () => process.env.TURSO_DB_URL ?? "https://your-db.turso.io"` or throw your own descriptive error before Turso does

Example fix

// before
const db = new Database("app.db", {
  url: () => process.env.TURSO_DB_URL ?? null, // throws when env unset
  authToken,
  remoteWritesExperimental: true,
});

// after
if (!process.env.TURSO_DB_URL) throw new Error("TURSO_DB_URL is required");
const db = new Database("app.db", {
  url: process.env.TURSO_DB_URL,
  authToken,
  remoteWritesExperimental: true,
});
Defensive patterns

Strategy: validation

Validate before calling

// Resolve and check the URL yourself before handing it to the constructor
const resolveUrl = (url: string | (() => string | null)): string => {
  const resolved = typeof url === 'function' ? url() : url;
  if (resolved == null) {
    throw new Error(`Sync URL resolved to null — check TURSO_DB_URL in ${import.meta.env.MODE} mode`);
  }
  return resolved;
};

const db = new Database(path, {
  url: resolveUrl(opts.url),
  authToken,
  remoteWritesExperimental: true,
});

Prevention

When it happens

Trigger: Passing `url: () => process.env.TURSO_DB_URL ?? null` (or any function that can return null) while the environment variable is unset; a URL function that reads config that is not yet loaded at database construction time; SSR or test environments where the env var is never injected.

Common situations: Missing .env entries in CI or a teammate's machine; deploying with a different env-var name than the code reads (TURSO_DB_URL vs DATABASE_URL); using a function form of url for the first time and forgetting the null branch; preview/staging environments that never received the sync URL.

Related errors


AI-assisted analysis of tursodatabase/turso@bad083fafb (2026-08-16). Data as JSON: /api/errors/dc5dccebf9ebfbb5. Report an issue: GitHub.