Describe the bug
On a WebContainer runtime (StackBlitz), a page that awaits a remote query() and then renders a remote form() in the same SSR pass throws:
Error: Cannot access event.url in a query. Pass the value as an argument to the query instead
No user code reads event.url. Kit's form.action getter does, to build the ?/remote=… action:
// packages/kit/src/runtime/app/server/remote/form.js
get: () => {
const search = new URLSearchParams(get_request_store().event.url.search); // <- throws
...
}
That read is guarded to throw while a query is running (is_in_remote_query):
// packages/kit/src/runtime/app/server/remote/shared.js
if (state.is_in_remote_query) {
for (const property of ["url", "params", "route"]) {
Object.defineProperty(derived, property, {
get() {
throw new Error(
`Cannot access event.${property} in a query. Pass the value as an argument to the query instead`,
);
},
});
}
}
Normally the query's request store is scoped to the query callback and cleared afterward, so the later form.action read sees the page's store (is_in_remote_query === false). In a WebContainer the ambient store is a module global that is never reset on purpose:
// packages/kit/src/exports/internal/server/event.js
export function with_request_store(store, fn) {
try {
sync_store = store;
return als ? als.run(store, fn) : fn();
} finally {
// Since AsyncLocalStorage is not working in webcontainers, we don't reset `sync_store`
// and handle only one request at a time in `src/runtime/server/index.js`.
if (!IN_WEBCONTAINER) {
sync_store = null;
}
}
}
// IN_WEBCONTAINER = !!globalThis.process?.versions?.webcontainer
After await getData() returns, sync_store still points at the query's store (is_in_remote_query === true) and is never restored. When the component then renders <form {...myForm}>, form.action → get_request_store().event.url hits that leftover query store and throws. Under export const csr = false this happens during pure SSR, so the page 500s.
On a runtime with real AsyncLocalStorage (normal Node) the finally resets sync_store and ALS scopes the store to the query callback. Same code renders fine there. This only reproduces in WebContainer / StackBlitz as far as I can see.
Reproduction
Minimal case: a .remote.ts with a query and a form, plus a page that awaits the query then renders the form.
// src/routes/data.remote.ts
import { query, form } from "$app/server";
export const getData = query(() => ({ title: "Ada" }));
export const save = form("unchecked", async () => {});
<!-- src/routes/+page.svelte -->
<script lang="ts">
import { getData, save } from './data.remote';
const data = await getData(); // top-level await (Svelte experimental.async)
</script>
<form {...save}>
<!-- rendering the form reads form.action -> event.url -->
<input {...save.fields.title.as('text', data.title)} />
<button>Save</button>
</form>
Needs experimental.async (Svelte compiler) and experimental.remoteFunctions (Kit). Add export const csr = false; in +page.ts to force pure SSR, then it 500s every time on StackBlitz. On local Node it returns 200.
Existing repro that hits this: any no-js (csr = false) route in
https://github.com/janekprange/sveltekit-remote-form-post-success-rehydrate
500s on StackBlitz (500 GET /default/no-js) but works locally on Node.
Logs
Error: Cannot access event.url in a query. Pass the value as an argument to the query instead
at eval (src/lib/SettingsForm.svelte:122:67)
500 GET /default/no-js
System Info
Binaries:
Node: 25.2.1
pnpm: 10.31.0
npmPackages:
@sveltejs/adapter-auto: next => 8.0.0-next.3
@sveltejs/kit: next => 3.0.0-next.23
@sveltejs/vite-plugin-svelte: ^7.2.0 => 7.3.0
svelte: ^5.56.7 => 5.56.9
vite: ^8.1.5 => 8.2.1
Only reproduces on WebContainer runtimes (StackBlitz). Same code is fine on a normal Node runtime (dev and production build).
Severity
serious, but I can work around it
Additional Information
Related:
Describe the bug
On a WebContainer runtime (StackBlitz), a page that awaits a remote
query()and then renders a remoteform()in the same SSR pass throws:No user code reads
event.url. Kit'sform.actiongetter does, to build the?/remote=…action:That read is guarded to throw while a query is running (
is_in_remote_query):Normally the query's request store is scoped to the query callback and cleared afterward, so the later
form.actionread sees the page's store (is_in_remote_query === false). In a WebContainer the ambient store is a module global that is never reset on purpose:After
await getData()returns,sync_storestill points at the query's store (is_in_remote_query === true) and is never restored. When the component then renders<form {...myForm}>,form.action→get_request_store().event.urlhits that leftover query store and throws. Underexport const csr = falsethis happens during pure SSR, so the page 500s.On a runtime with real
AsyncLocalStorage(normal Node) thefinallyresetssync_storeand ALS scopes the store to the query callback. Same code renders fine there. This only reproduces in WebContainer / StackBlitz as far as I can see.Reproduction
Minimal case: a
.remote.tswith aqueryand aform, plus a page that awaits the query then renders the form.Needs
experimental.async(Svelte compiler) andexperimental.remoteFunctions(Kit). Addexport const csr = false;in+page.tsto force pure SSR, then it 500s every time on StackBlitz. On local Node it returns 200.Existing repro that hits this: any
no-js(csr = false) route inhttps://github.com/janekprange/sveltekit-remote-form-post-success-rehydrate
500s on StackBlitz (
500 GET /default/no-js) but works locally on Node.Logs
System Info
Severity
serious, but I can work around it
Additional Information
Related:
event.url,event.paramsandevent.routeaccess inside queries #16452 — introduced theevent.url/event.params/event.routethrow inside queriesevent.url.pathnameshould be hidden inside a query #16416 — requested hidingurlinside a queryurlin remote functions (feature request, different concern)