diff --git a/.changeset/good-pianos-jump.md b/.changeset/good-pianos-jump.md
new file mode 100644
index 0000000000..0ae35e5937
--- /dev/null
+++ b/.changeset/good-pianos-jump.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: check that snippet is not rendered as a component
diff --git a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js
index b830367776..66ec08d782 100644
--- a/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js
+++ b/packages/svelte/src/compiler/phases/3-transform/client/visitors/template.js
@@ -850,7 +850,14 @@ function serialize_inline_component(node, component_name, context) {
b.thunk(b.array(props_and_spreads.map((p) => (Array.isArray(p) ? b.object(p) : p))))
);
/** @param {import('estree').Identifier} node_id */
- let fn = (node_id) => b.call(component_name, node_id, props_expression);
+ let fn = (node_id) =>
+ b.call(
+ context.state.options.dev
+ ? b.call('$.validate_component', b.id(component_name))
+ : component_name,
+ node_id,
+ props_expression
+ );
if (bind_this !== null) {
const prev = fn;
diff --git a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js
index ffba6d09db..c0eebce99a 100644
--- a/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js
+++ b/packages/svelte/src/compiler/phases/3-transform/server/transform-server.js
@@ -882,7 +882,12 @@ function serialize_inline_component(node, component_name, context) {
/** @type {import('estree').Statement} */
let statement = b.stmt(
(typeof component_name === 'string' ? b.call : b.maybe_call)(
- component_name,
+ context.state.options.dev
+ ? b.call(
+ '$.validate_component',
+ typeof component_name === 'string' ? b.id(component_name) : component_name
+ )
+ : component_name,
b.id('$$payload'),
props_expression
)
diff --git a/packages/svelte/src/internal/client/validate.js b/packages/svelte/src/internal/client/validate.js
index 5c0378920e..831ccd9014 100644
--- a/packages/svelte/src/internal/client/validate.js
+++ b/packages/svelte/src/internal/client/validate.js
@@ -102,13 +102,13 @@ export function loop_guard(timeout) {
};
}
-const symbol = Symbol.for('svelte.snippet');
+const snippet_symbol = Symbol.for('svelte.snippet');
/**
* @param {any} fn
*/
export function add_snippet_symbol(fn) {
- fn[symbol] = true;
+ fn[snippet_symbol] = true;
return fn;
}
@@ -117,7 +117,7 @@ export function add_snippet_symbol(fn) {
* @param {any} snippet_fn
*/
export function validate_snippet(snippet_fn) {
- if (snippet_fn[symbol] !== true) {
+ if (snippet_fn[snippet_symbol] !== true) {
throw new Error(
'The argument to `{@render ...}` must be a snippet function, not a component or some other kind of function. ' +
'If you want to dynamically render one snippet or another, use `$derived` and pass its result to `{@render ...}`.'
@@ -125,3 +125,14 @@ export function validate_snippet(snippet_fn) {
}
return snippet_fn;
}
+
+/**
+ * Validate that the function behind `
hello
+{/snippet} + +