sveltejs/kit · error · Error

exports is not available in dev mode

Error message

exports is not available in dev mode

What it means

The `exports` binding of the cloudflare:workers virtual module is only meaningful in the deployed/preview Workers runtime where the Worker's actual exports exist. In `vite dev` there is no built-and-deployed Worker to export, so the adapter substitutes a Proxy whose get trap unconditionally throws. Accessing any property on `exports` during dev therefore fails with this message.

Source

Thrown at packages/adapter-cloudflare/src/virtual-cloudflare-workers.js:115

	if (!proxy) {
		throw new Error(`Cannot access cloudflare:workers in a prerenderable route`);
	}
	return als.run(newEnv, fn);
}
/** @type {Module['withEnvAndExports']} */
export function withEnvAndExports(newEnv, _, fn) {
	if (!proxy) {
		throw new Error(`Cannot access cloudflare:workers in a prerenderable route`);
	}
	return als.run(newEnv, fn);
}

// no-ops
export const exports = new Proxy(
	{},
	{
		get() {
			throw new Error('exports is not available in dev mode');
		},
		has() {
			throw new Error('exports is not available in dev mode');
		}
	}
);
/** @type {Module['waitUntil']} */
export function waitUntil() {}
/** @type {Module['cache']} */
export const cache = {
	purge() {
		return Promise.resolve({ success: true, errors: [] });
	}
};
class Span {
	get isTraced() {
		return false;
	}

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Remove the `exports` usage from SvelteKit server code — use service bindings configured in wrangler.jsonc instead of self-referencing exports.
  2. Guard the access so it only runs in the deployed runtime: if (import.meta.env.DEV) skip or mock the exports usage.
  3. Test the exports-dependent path with `wrangler dev` on a built worker instead of `vite dev`.
  4. Provide a dev-mode stub: wrap the import in a module that returns a mock during dev.

Example fix

// before
import { exports } from 'cloudflare:workers';
const worker = exports.default;

// after
import { env } from 'cloudflare:workers'; // use bindings instead, or guard:
let worker;
if (!import.meta.env.DEV) {
  const { exports } = await import('cloudflare:workers');
  worker = exports.default;
}
Defensive patterns

Strategy: fallback

Validate before calling

if (import.meta.env.DEV) {
  console.warn('cloudflare:workers exports is unavailable in dev; skipping');
}

Type guard

function exportsAvailable() {
  return typeof import.meta !== 'undefined' && !import.meta.env.DEV;
}

Try / catch

try {
  const { exports } = await import('cloudflare:workers');
  return exports.default;
} catch (e) {
  if (e.message.includes('not available in dev mode')) return devStubWorker;
  throw e;
}

Prevention

When it happens

Trigger: Importing { exports } from 'cloudflare:workers' in dev mode and reading any property of it (e.g. exports.default, named worker exports) from a load function, endpoint, or module-scope code running under `vite dev`.

Common situations: Code written for a Workers-only project uses `exports` to self-reference the Worker (e.g. for worker-to-worker RPC via CloudflareServiceBinding) and is reused inside a SvelteKit dev session; accessing `exports.default` to call the current worker.

Related errors


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/b68affb2716a343e. Report an issue: GitHub.