diff --git a/.changeset/flat-ducks-attack.md b/.changeset/flat-ducks-attack.md new file mode 100644 index 000000000000..5eeb7cfded92 --- /dev/null +++ b/.changeset/flat-ducks-attack.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: ensure rendering starts off synchronously diff --git a/packages/kit/src/exports/internal/event.js b/packages/kit/src/exports/internal/event.js index f884e6ab6407..c66bc4435aed 100644 --- a/packages/kit/src/exports/internal/event.js +++ b/packages/kit/src/exports/internal/event.js @@ -45,7 +45,17 @@ export function getRequestEvent() { export function get_request_store() { const result = try_get_request_store(); if (!result) { - throw new Error('Could not get the request store. This is an internal error.'); + let message = 'Could not get the request store.'; + + if (als) { + message += ' This is an internal error.'; + } else { + message += + ' In environments without `AsyncLocalStorage`, the request store (used by e.g. remote functions) must be accessed synchronously, not after an `await`.' + + ' If it was accessed synchronously then this is an internal error.'; + } + + throw new Error(message); } return result; } diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index 7a2a366de8f5..178a26b23616 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -205,7 +205,16 @@ export async function render_response({ // portable as possible, but reset afterwards if (paths.relative) paths.override({ base, assets }); - const rendered = options.root.render(props, render_opts); + const maybe_promise = options.root.render(props, render_opts); + // We have to invoke .then eagerly here in order to kick off rendering: it's only starting on access, + // and `await maybe_promise` would eagerly access the .then property but call its function only after a tick, which is too late + // for the paths.reset() below and for any eager getRequestEvent() calls during rendering without AsyncLocalStorage available. + const rendered = + options.async && 'then' in maybe_promise + ? /** @type {ReturnType & Promise} */ ( + maybe_promise + ).then((r) => r) + : maybe_promise; // TODO 3.0 remove options.async if (options.async) {