tursodatabase/turso · error
remoteWritesExperimental requires a non-null URL
Error message
remoteWritesExperimental requires a non-null URL
What it means
When remoteWritesExperimental is enabled, the constructor must resolve a concrete remote URL before creating the RemoteWriter. url may be supplied as a lazy resolver function; if calling it yields null or undefined, resolveUrl fails fast (promise-turbopack-hack.ts:41-50) because a null endpoint must never reach the writer. A plain-string url is accepted as-is and never triggers this error.
Solutions
- Set the environment/config value the resolver reads so it is non-null in every build mode where remoteWritesExperimental is on
- Pass the URL as a plain string when it is already known at construction time
- Enable remoteWritesExperimental conditionally, only after your own code confirms the resolved URL is non-null
Example fix
// before
const db = new Database({
path: "local.db",
remoteWritesExperimental: true,
url: () => import.meta.env.VITE_TURSO_DB_URL, // undefined in prod
});
// after
const url = import.meta.env.VITE_TURSO_DB_URL;
if (url == null) throw new Error("VITE_TURSO_DB_URL is not set");
const db = new Database({
path: "local.db",
remoteWritesExperimental: true,
url,
}); Defensive patterns
Strategy: validation
Validate before calling
// Resolve and verify before enabling remote writes
const resolvedUrl = typeof url === "function" ? url() : url;
if (resolvedUrl == null) {
throw new Error("remoteWritesExperimental needs a URL; check your env/config");
}
const db = new Database({
path,
url: resolvedUrl,
authToken,
remoteWritesExperimental: true,
}); Try / catch
try {
const db = new Database({ path, url, remoteWritesExperimental: true });
} catch (err) {
if (err instanceof Error && err.message.includes("non-null URL")) {
// URL resolver returned null: fail startup with a clearer message
throw new Error("Missing remote database URL (check env vars for this build mode)");
}
throw err;
} Prevention
- Validate that the env/config value behind the url resolver is set for every build mode before constructing
- Pass a plain string url when the endpoint is known statically
- Keep a single config module that asserts required variables at startup instead of returning null silently
When it happens
Trigger: new Database({ ..., remoteWritesExperimental: true, url: () => import.meta.env.VITE_TURSO_DB_URL }) where the variable is undefined in some build mode; a resolver reading asynchronously-loaded config before it is ready; a placeholder () => null that was never replaced.
Common situations: Environment variable defined for dev but missing in preview/production builds; config fetched at runtime so the resolver runs before the value exists; bundler-specific entry (turbopack dev server) where env injection behaves differently than expected.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- remoteWritesExperimental requires a non-null URL
- HTTP request missing URL: no URL in request and no baseUrl…
- MISSING_URL
- The sync remote URL must be absolute.
- transactionAsync is not supported with…
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20).
Data as JSON: /api/errors/c9c293c8444621ad.
Report an issue: GitHub.
Appendix: source
Thrown at bindings/javascript/sync/packages/wasm/promise-turbopack-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 6c72522679)