Repository: sveltejs/svelte (JavaScript)

Issue:
Svelte 5: you can mount a snippet
### Describe the bug

If a snippet doesn't have arguments, you can successfully mount it despite snippets and components being non-interchangeable.

### Reproduction

[REPL](https://svelte-5-preview.vercel.app/#H4sIAAAAAAAAA0WPz2rDMAzGX8VoFwfCcs_SwAY99NAnmHcosVIM8R9spawYv_usLKEH8en7SR-WM8xmwQT9dwZ3swg9fIYALdAzsEkPXAirT36NE5MhTdEEGpVTZGzwkUT27upXR62wLEXM0Vuh9rACXuXa16RsxGkUecO0RWRyJrQHUkS3eEfqhfbTatHRe3XnBbn9el60VECYSEHT_idK88HNJkP3utAN2jyE0acjMA5dJdsov_GjAUmwyqYodwDC33pw7nZf6v-t12Y2qKGnuGL5KX9Gp7FpOgEAAA==)

### Logs

_No response_

### System Info

```shell
Svelte v5.0.0-next.110
```


### Severity

annoyance


Discussion:

Patch:
diff --git a/.changeset/itchy-panthers-shave.md b/.changeset/itchy-panthers-shave.md
new file mode 100644
index 000000000000..c47ab1f61ccc
--- /dev/null
+++ b/.changeset/itchy-panthers-shave.md
@@ -0,0 +1,5 @@
+---
+"svelte": patch
+---
+
+fix: disallow mounting a snippet
diff --git a/packages/svelte/src/internal/client/render.js b/packages/svelte/src/internal/client/render.js
index c0d449f35bc0..bafaadf2b8f2 100644
--- a/packages/svelte/src/internal/client/render.js
+++ b/packages/svelte/src/internal/client/render.js
@@ -21,6 +21,7 @@ import { handle_event_propagation } from './dom/elements/events.js';
 import { reset_head_anchor } from './dom/blocks/svelte-head.js';
 import * as w from './warnings.js';
 import * as e from './errors.js';
+import { validate_component } from '../shared/validate.js';
 
 /** @type {Set<string>} */
 export const all_registered_events = new Set();
@@ -102,6 +103,10 @@ export function stringify(value) {
  * @returns {Exports}
  */
 export function mount(component, options) {
+	if (DEV) {
+		validate_component(component);
+	}
+
 	const anchor = options.anchor ?? options.target.appendChild(empty());
 	// Don't flush previous effects to ensure order of outer effects stays consistent
 	return flush_sync(() => _mount(component, { ...options, anchor }), false);
@@ -125,6 +130,10 @@ export function mount(component, options) {
  * @returns {Exports}
  */
 export function hydrate(component, options) {
+	if (DEV) {
+		validate_component(component);
+	}
+
 	const target = options.target;
 	const previous_hydrate_nodes = hydrate_nodes;
 


Test patch:
diff --git a/packages/svelte/tests/runtime-runes/samples/mount-snippet-error/_config.js b/packages/svelte/tests/runtime-runes/samples/mount-snippet-error/_config.js
new file mode 100644
index 000000000000..3ba2b358ea52
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/mount-snippet-error/_config.js
@@ -0,0 +1,12 @@
+import { test } from '../../test';
+
+export default test({
+	compileOptions: {
+		dev: true
+	},
+	async test({ assert, target }) {
+		const div = target.querySelector('div');
+		assert.htmlEqual(div?.innerHTML || '', '');
+	},
+	runtime_error: 'snippet_used_as_component\nA snippet must be rendered with `{@render ...}`'
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/mount-snippet-error/main.svelte b/packages/svelte/tests/runtime-runes/samples/mount-snippet-error/main.svelte
new file mode 100644
index 000000000000..075fbba24ee8
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/mount-snippet-error/main.svelte
@@ -0,0 +1,14 @@
+<script>
+    import { onMount, mount } from 'svelte';
+
+    let el;
+
+    onMount(() => {
+        mount(foo, { target: el });
+    });
+</script>
+
+<div bind:this={el}></div>
+{#snippet foo()}
+    shouldnt be rendered
+{/snippet}
\ No newline at end of file