ciscoheat/sveltekit-flash-message

Error: getFlash options can only be set at the first call to getFlash.

abishekdevendran opened this issue · 9 comments

I'm using the getFlash component in clientside(root +layout.svelte) as such:

        import { getFlash } from 'sveltekit-flash-message/client';

	const flash = getFlash(page, {
		clearOnNavigate: true
	});

	$: if ($flash) {
		switch ($flash.type) {
			case 'success':
				toast.success($flash.message);
				break;
			case 'error':
				toast.error($flash.message);
				break;
			default:
				toast.info($flash.message);
		}
	}

The code generally works for the most part, but when I make changes to seemingly unrelated +page.svelte or deeper components during dev, this error pops up. I'm not sure if this is a user error, but the error itself is frequent enough to be disruptive(cannot proceed without dev server restart).

This happens when a site has multiple branching routes (like an app route and an admin route), and you browse between them in the same session, so $page refers to the same object. I'll try to come up with a fix for that soon.

Should be fixed now in 2.2.2. If you still get the error, are you using getFlash options on more than one page in the route? (clearOnNavigate is default true, so you can remove that)

CrlH commented

I get a similar issue, still present using sveltekit-flash-message@2.3.0 using the server-side approach as documented.
Note: It does look like this is only thrown when an HTTP error page (4xx, 5xx) is rendered... TBC.

As per your last comment, @ciscoheat, no other options initializer is present.

src/routes/+layout.server.ts

import { loadFlash, flashCookieOptions } from 'sveltekit-flash-message/server';

flashCookieOptions.secure = false;

export const load = loadFlash(() => {});

Stack trace

Error: getFlash options can only be set once, at a top-level component.
    at _initFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_modules
/sveltekit-flash-message/dist/client.js:38:15)
    at Module.getFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_mo
dules/sveltekit-flash-message/dist/client.js:124:12)
    at src/routes/+layout.svelte:8:17
    at Object.$$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)  
    at .svelte-kit/generated/root.svelte:45:40
    at $$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)
    at Object.render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:164:17)    
    at Module.render_response (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4
.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:171:29)
    at async Module.render_page (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte
@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:284:10)
    at async resolve (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4.2.8_vite
@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/respond.js:409:18)
Error: getFlash options can only be set once, at a top-level component.
    at _initFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_modules
/sveltekit-flash-message/dist/client.js:38:15)
    at Module.getFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_mo
dules/sveltekit-flash-message/dist/client.js:124:12)
    at src/routes/+layout.svelte:8:17
    at Object.$$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)  
    at .svelte-kit/generated/root.svelte:45:40
    at $$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)
    at Object.render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:164:17)    
    at Module.render_response (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4
.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:171:29)
    at async Module.respond_with_error (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1
_svelte@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/respond_with_error.js:83:10)
    at async Module.render_page (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte
@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:303:10)
Error: getFlash options can only be set once, at a top-level component.
    at _initFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_modules
/sveltekit-flash-message/dist/client.js:38:15)
    at Module.getFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_mo
dules/sveltekit-flash-message/dist/client.js:124:12)
    at src/routes/+layout.svelte:8:17
    at Object.$$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)  
    at .svelte-kit/generated/root.svelte:45:40
    at $$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)
    at Object.render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:164:17)    
    at Module.render_response (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4
.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:171:29)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Module.render_page (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte
@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/index.js:284:10)
Error: getFlash options can only be set once, at a top-level component.
    at _initFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_modules
/sveltekit-flash-message/dist/client.js:38:15)
    at Module.getFlash (node_modules/.pnpm/sveltekit-flash-message@2.3.0_@sveltejs+kit@2.0.2_svelte@4.2.8/node_mo
dules/sveltekit-flash-message/dist/client.js:124:12)
    at src/routes/+layout.svelte:8:17
    at Object.$$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)  
    at .svelte-kit/generated/root.svelte:45:40
    at $$render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:156:16)
    at Object.render (node_modules/.pnpm/svelte@4.2.8/node_modules/svelte/src/runtime/internal/ssr.js:164:17)    
    at Module.render_response (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1_svelte@4
.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/render.js:171:29)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Module.respond_with_error (node_modules/.pnpm/@sveltejs+kit@2.0.2_@sveltejs+vite-plugin-svelte@3.0.1
_svelte@4.2.8_vite@5.0.10/node_modules/@sveltejs/kit/src/runtime/server/page/respond_with_error.js:83:10)

@CrlH Are you setting the getFlash options in another layout, or none at all? If you can reproduce this in a repo, that'd be much appreciated.

CrlH commented

Aha - my bad: while preparing a repo, I did find a getFlash that sets clearAfterMs, like this:

<script lang="ts">
  import { getFlash } from 'sveltekit-flash-message/client';
  import { page } from '$app/stores';

  const flash = getFlash(page, {
    clearAfterMs: 10000,
  });
</script>

For me it made sense to set flashCookieOptions server-side, but this appears to be the only option you can set server-side... Meaning this behavior prevents you from setting other options on the client side, right? 😕

Might be good to add a(nother) note to the docs, or to consider other options on server side too... Though I'd have to admit that things like clearAfterMs make a lot less sense server-side. 🤓

The only common option for server and client are the cookies. Maybe there can be a similar cookie option for the client as on the server, to separate them from the other options.

CrlH commented

Thanks! I’ll change my app to have flashCookieOptions to be handled on client-site.

But it looks like one that sets flashCookieOptions server-side can’t set other options… That’s limiting, no?

What other options on the server are there?

CrlH commented

Actually, I meant to say - if you choose to set flashCookieOptions server-side, you can't set any other option on the client-side, because options can only be set the first time you call getFlash.

At least, that was my assumption until now. I can consistently reproduce this in my project, but I can't seem to consistently reproduce the same in an example repo (yet), so there might be a more complex cause for my output above... I can't share the entire project here, but in short:

Project Setup

  1. I set flashCookieOptions server-side on the root layout server file
  2. I set clearAfterMs client-side on the root layout file
  3. The page that produces the output is nested and has one additional +layout.server.ts where I await the parent load
  4. The nested layout file does not contain any reference to getFlash

Findings so far

  1. The output above has only shown in combination with a HTTP 500 error page - for which I have no dedicated files (so sveltekit default)
  2. If I remove clearAfterMs from the client-side, the error doesn't occur.

I'll try to dig into it next week and update you if I come across something. Tips are welcome, should you think of something. 😉

Happy holidays! 🎅