adapter-cloudflare 8: concurrent Vite servers each start a platform proxy, so Vitest projects collide on the same SQLite (SQLITE_BUSY_RECOVERY)
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 70/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- javascript, sqlite, vite
- Domain
- tooling
Research direction
Start in the adapter-cloudflare plugin source defining virtual_workers_module(): setup() guards on globalThis.__sveltekit_cloudflare_platform but only assigns it after awaiting getPlatformProxy, and dispose() releases it. Cache the in-flight getPlatformProxy promise instead and clear it in dispose, as the suggested patch does. Reproduce with a two-project Vitest config (client/server) extending sveltekit({ adapter: adapter() }); run vitest --run repeatedly after a vite dev. Done looks like one 'Using secrets defined in .dev.vars' line, no SQLITE_BUSY, no exit warning. Context: #16623, #17238.
Written by the indexing model from the issue text.
Description
Describe the bug
virtual_workers_module()'s setup() guards on globalThis.__sveltekit_cloudflare_platform and only assigns it after await getPlatformProxy(options) has finished:
const setup = async () => {
if (globalThis.__sveltekit_cloudflare_platform) return;
const proxy = await getPlatformProxy(options);
globalThis.__sveltekit_cloudflare_platform = proxy;
...
};
When two Vite servers start in the same process, both pass the guard before either finishes, so each starts its own getPlatformProxy() (its own workerd) on the same .wrangler/state. This is the same shape as #16623 (which described the old emulate() path), but in the new Vite plugin. Vitest triggers it every time: each project that extends a config using sveltekit({ adapter: adapter() }) gets its own Vite server, so a two-project setup (say client and server) starts two proxies at once.
The result is intermittent. Most often one workerd is repairing a journal left by an earlier unclean shutdown (a killed vite dev, say) while the other opens the same SQLite files, and the run dies in about two seconds:
Using secrets defined in .dev.vars
Using secrets defined in .dev.vars
*** Fatal uncaught kj::Exception: workerd/util/sqlite.c++:890: failed: SQLite failed; dbErrorMessage(prepareResult, db) = database is locked: SQLITE_BUSY (extended: SQLITE_BUSY_RECOVERY)
⎯⎯⎯⎯⎯⎯⎯ Startup Error ⎯⎯⎯⎯⎯⎯⎯⎯
AggregateError: Failed to initialize projects. There were errors during projects setup.
MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start.
... at getPlatformProxy
When it doesn't fail, the run still ends with Tests closed successfully but something prevents the main process from exiting, even with the dispose fix from #17238.
Reproduction
-
A SvelteKit 3 project with
@sveltejs/adapter-cloudflare8.0.0 and awrangler.jsoncwith a D1 binding. -
A
vite.config.tswithsveltekit({ adapter: adapter() })and two Vitest projects thatextendsit:test: { projects: [ { extends: './vite.config.ts', test: { name: 'client', /* browser */ } }, { extends: './vite.config.ts', test: { name: 'server', environment: 'node' } }, ] } -
vitest --runrepeatedly. The setup prints "Using secrets defined in .dev.vars" twice (or two proxies in whatever form your logs show).
In my project, 3 of 5 consecutive runs failed this way (about 2 s each); the other two passed in about 19 s with the exit warning above. Failures are most likely right after vite dev, wrangler dev or a build, which leave state behind.
Suggested fix
Store the pending promise rather than the finished proxy, so concurrent servers share one proxy. I patched my local copy of 8.0.0 this way:
const setup = async () => {
if (globalThis.__sveltekit_cloudflare_platform) return;
const pending = (globalThis.__sveltekit_cloudflare_platform_pending ??= getPlatformProxy(options));
const proxy = await pending;
if (globalThis.__sveltekit_cloudflare_platform) return;
globalThis.__sveltekit_cloudflare_platform = proxy;
globalThis.caches = proxy.caches;
};
(dispose would also need to clear the pending promise.) With it, 5 of 5 runs started a single proxy, none failed, each took about 7 s instead of 19 s, and the exit warning was gone. I haven't checked the preview server or a restarting dev server.
Workaround for now: leave the adapter out of the Vite config when process.env.VITEST is set. Unit tests that don't need bindings don't need the proxy at all.
System Info
@sveltejs/kit 3.0.0, @sveltejs/adapter-cloudflare 8.0.0, wrangler 4.147.0
vite 8.3.2, vitest 4.1.11, @vitest/browser-playwright 4.1.11
node 26.10.0, bun 1.4.2, macOS 27.0.1
Severity
annoyance (intermittent test-start failure with a workaround)
- Dominant language
- JavaScript
- Stars
- 20.9k
- Forks
- 2.4k
- Avg merge
- 1d 23h
- Merged PRs (30d)
- 89
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from sveltejs/kit
-
awaiting submitter
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
adapter-cloudflare: `cloudflare:workers` keeps using the old platform proxy after the Wrangler config reloads in devPossibly taken @svelte-triage-bot claimed this 3 days ago. Openpkg:adapter-cloudflare
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
svelte-package watch mode leaves the compiled .js of a deleted .ts file in the outputPossibly taken @svelte-triage-bot claimed this 4 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
Maintainers usually reply within 1 day
-
types / typescript
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
Maintainers usually reply within 1 day
-
Prerendering no longer shows progressMay be free again A pull request for this issue was closed without being merged. Open
Difficulty 2/5 1-3 hours Newbie friendliness 64/100
sveltejs/kit#17163 · 4 comments ·
Maintainers usually reply within 1 day
Similar issues
-
bug confirmed issue
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
open-webui/open-webui#33196 · 2 comments ·
Maintainers usually reply within 1 day
-
area: apple-music area: build-release bug effort: small priority: high
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
ChristianTabor/Argon#32 ·
Maintainers usually reply within 1 day
-
0️⃣ phase/new
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100