diff --git a/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts
index 015df1a722..5d39e97033 100644
--- a/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts
+++ b/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts
@@ -504,7 +504,7 @@ function codegenReactiveScope(
if (testCondition === null) {
CompilerError.invariant(firstOutputIndex !== null, {
reason: `Expected scope to have at least one declaration`,
- description: `Scope '@{scope.id} has no declarations`,
+ description: `Scope '@${scope.id}' has no declarations`,
loc: null,
suggestions: null,
});
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-no-declarations-in-reactive-scope-with-early-return.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-no-declarations-in-reactive-scope-with-early-return.expect.md
new file mode 100644
index 0000000000..335b09d320
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-no-declarations-in-reactive-scope-with-early-return.expect.md
@@ -0,0 +1,121 @@
+
+## Input
+
+```javascript
+// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
+function Component() {
+ const items = useItems();
+ const filteredItems = useMemo(
+ () =>
+ items.filter(([item]) => {
+ return item.name != null;
+ }),
+ [item]
+ );
+
+ if (filteredItems.length === 0) {
+ // note: this must return nested JSX to create the right scope
+ // shape that causes no declarations to be emitted
+ return (
+
+
+
+ );
+ }
+
+ return (
+ <>
+ {filteredItems.map(([item]) => (
+
+ ))}
+ >
+ );
+}
+
+```
+
+## Code
+
+```javascript
+import { unstable_useMemoCache as useMemoCache } from "react"; // @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
+function Component() {
+ const $ = useMemoCache(9);
+ const items = useItems();
+ let t0;
+ let t1;
+ let t2;
+ if ($[0] !== items) {
+ t2 = Symbol.for("react.early_return_sentinel");
+ bb14: {
+ let t3;
+ if ($[4] === Symbol.for("react.memo_cache_sentinel")) {
+ t3 = (t4) => {
+ const [item] = t4;
+ return item.name != null;
+ };
+ $[4] = t3;
+ } else {
+ t3 = $[4];
+ }
+ t0 = items.filter(t3);
+ const filteredItems = t0;
+ if (filteredItems.length === 0) {
+ let t4;
+ if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
+ t4 = (
+
+
+
+ );
+ $[5] = t4;
+ } else {
+ t4 = $[5];
+ }
+ t2 = t4;
+ break bb14;
+ }
+ let t4;
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
+ t4 = (t5) => {
+ const [item_0] = t5;
+ return ;
+ };
+ $[6] = t4;
+ } else {
+ t4 = $[6];
+ }
+ t1 = filteredItems.map(t4);
+ }
+ $[0] = items;
+ $[1] = t1;
+ $[2] = t2;
+ $[3] = t0;
+ } else {
+ t1 = $[1];
+ t2 = $[2];
+ t0 = $[3];
+ }
+ if (t2 !== Symbol.for("react.early_return_sentinel")) {
+ return t2;
+ }
+ let t3;
+ if ($[7] !== t1) {
+ t3 = <>{t1}>;
+ $[7] = t1;
+ $[8] = t3;
+ } else {
+ t3 = $[8];
+ }
+ return t3;
+}
+
+```
+
+### Eval output
+(kind: exception) Fixture not implemented!
+logs: ['The above error occurred in the component:\n' +
+ '\n' +
+ ' at WrapperTestComponent (/packages/snap/dist/sprout/evaluator.js:54:26)\n' +
+ '\n' +
+ 'Consider adding an error boundary to your tree to customize error handling behavior.\n' +
+ 'Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.']
\ No newline at end of file
diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-no-declarations-in-reactive-scope-with-early-return.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-no-declarations-in-reactive-scope-with-early-return.js
new file mode 100644
index 0000000000..1d01c20993
--- /dev/null
+++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/repro-no-declarations-in-reactive-scope-with-early-return.js
@@ -0,0 +1,29 @@
+// @enableAssumeHooksFollowRulesOfReact @enableTransitivelyFreezeFunctionExpressions
+function Component() {
+ const items = useItems();
+ const filteredItems = useMemo(
+ () =>
+ items.filter(([item]) => {
+ return item.name != null;
+ }),
+ [item]
+ );
+
+ if (filteredItems.length === 0) {
+ // note: this must return nested JSX to create the right scope
+ // shape that causes no declarations to be emitted
+ return (
+
+
+
+ );
+ }
+
+ return (
+ <>
+ {filteredItems.map(([item]) => (
+
+ ))}
+ >
+ );
+}