diff --git a/typo3/sysext/core/Classes/Routing/PageRouter.php b/typo3/sysext/core/Classes/Routing/PageRouter.php
index 18ec33dbc1929536640763ff259393bc911f81ca..d80ce5d061390daefe6a54fd4f4847b6ecf13b0e 100644
--- a/typo3/sysext/core/Classes/Routing/PageRouter.php
+++ b/typo3/sysext/core/Classes/Routing/PageRouter.php
@@ -346,7 +346,10 @@ class PageRouter implements RouterInterface
                 if ($route->hasOption('deflatedParameters')) {
                     $parameters = $route->getOption('deflatedParameters');
                 }
-                $mappableProcessor->generate($route, $parameters);
+                // skip the route, in case any aspect of it could not be mapped to a value
+                if ($mappableProcessor->generate($route, $parameters) === false) {
+                    continue;
+                }
                 // ABSOLUTE_URL is used as default fallback
                 $urlAsString = $generator->generate($routeName, $parameters, $referenceType);
                 $uri = new Uri($urlAsString);
diff --git a/typo3/sysext/frontend/Tests/Functional/SiteHandling/EnhancerLinkGenerator/RouteTest.php b/typo3/sysext/frontend/Tests/Functional/SiteHandling/EnhancerLinkGenerator/RouteTest.php
index dc1c080f188869a8f0c01e4d9c2a4fa947002349..504d67050cfea3834f9a7f8b976abfc9feb8673a 100644
--- a/typo3/sysext/frontend/Tests/Functional/SiteHandling/EnhancerLinkGenerator/RouteTest.php
+++ b/typo3/sysext/frontend/Tests/Functional/SiteHandling/EnhancerLinkGenerator/RouteTest.php
@@ -453,4 +453,69 @@ final class RouteTest extends AbstractEnhancerLinkGeneratorTestCase
     {
         $this->assertGeneratedUriEquals($testSet);
     }
+
+    public static function outOfScopeValueIsNotMappedDataProvider(): array
+    {
+        // variables (applied when invoking expectations)
+        $variables = Variables::create()->define([
+            'value' => null, // defined via VariableContext
+            'routePrefix' => 'enhance',
+            'aspectName' => 'value',
+        ]);
+        $variableContexts = [];
+        $enhancers = Builder::create()->declareEnhancers();
+        foreach ($enhancers as $enhancer) {
+            $generatedParams = match ($enhancer->describe()) {
+                'Simple' => '&value=[[value]]',
+                'Plugin' => '&testing[value]=[[value]]',
+                'Extbase' => '&tx_testing_link[action]=index&tx_testing_link[controller]=Link&tx_testing_link[value]=[[value]]',
+                default => null,
+            };
+            if ($generatedParams === null) {
+                continue;
+            }
+            $variableContexts[] = VariablesContext::create(
+                Variables::create([
+                    'generatedParams' => VariableValue::createUrlEncodedParams($generatedParams, null, '?'),
+                ])
+            )->withRequiredApplicables($enhancer);
+        }
+        return Permutation::create($variables)
+            ->withTargets(
+                TestSet::create()
+                    ->withMergedApplicables(LanguageContext::create(0))
+                    ->withTargetPageId(1100)
+                    ->withUrl(
+                        VariableValue::create('https://acme.us/welcome[[generatedParams]]&cHash=')
+                    ),
+            )
+            ->withApplicableSet(
+                // value `5000` is out of scope for the given range `[1; 100]`
+                VariablesContext::create(Variables::create(['value' => 5000])),
+            )
+            ->withApplicableItems($enhancers)
+            ->withApplicableItems($variableContexts)
+            ->withApplicableSet(
+                AspectDeclaration::create('StaticRangeMapper')->withConfiguration([
+                    VariableItem::create('aspectName', [
+                        'type' => 'StaticRangeMapper',
+                        'start' => '1',
+                        'end' => '100',
+                    ]),
+                ])
+            )
+            ->permute()
+            ->getTargetsForDataProvider();
+    }
+
+    /**
+     * Asserts that value `5000` cannot generate a valid URL, having
+     * a `StaticRangeMapper` which only allows values in range `[1; 100]`.
+     */
+    #[DataProvider('outOfScopeValueIsNotMappedDataProvider')]
+    #[Test]
+    public function outOfScopeValueIsNotMapped(TestSet $testSet): void
+    {
+        $this->assertGeneratedUriEquals($testSet, false);
+    }
 }
diff --git a/typo3/sysext/frontend/Tests/Functional/SiteHandling/Framework/Builder/VariableValue.php b/typo3/sysext/frontend/Tests/Functional/SiteHandling/Framework/Builder/VariableValue.php
index 8298de23745023819972491499719556b622562c..843204e2e092be2e951c661995411f6bec95a517 100644
--- a/typo3/sysext/frontend/Tests/Functional/SiteHandling/Framework/Builder/VariableValue.php
+++ b/typo3/sysext/frontend/Tests/Functional/SiteHandling/Framework/Builder/VariableValue.php
@@ -40,10 +40,19 @@ class VariableValue
         return new static($value, $defaultVariables);
     }
 
+    public static function createUrlEncodedParams(
+        string $value,
+        Variables $defaultVariables = null,
+        string $prefix = '&'
+    ): self {
+        $value = self::urlEncodeParams($value, $prefix);
+        return self::create($value, $defaultVariables);
+    }
+
     private function __construct(string $value, Variables $defaultVariables = null)
     {
-        $variableNames = $this->extractVariableNames($value);
-        if (count($variableNames) === 0) {
+        $variableNames = self::extractVariableNames($value);
+        if ($variableNames === []) {
             throw new \LogicException(
                 sprintf(
                     'Payload did not contain any variables "%s"',
@@ -58,9 +67,15 @@ class VariableValue
         $this->defaultVariables = $defaultVariables;
     }
 
+    public function __toString(): string
+    {
+        return $this->value;
+    }
+
     public function apply(Variables $variables): string
     {
         $variables = $variables->withDefined($this->defaultVariables);
+        $variables = $this->resolveNestedVariables($variables);
 
         $this->assertVariableNames($variables);
         if (!$this->hasAllRequiredDefinedVariableNames($variables)) {
@@ -68,12 +83,25 @@ class VariableValue
         }
 
         return str_replace(
-            array_map([$this, 'wrap'], $variables->keys()),
+            array_map([self::class, 'wrap'], $variables->keys()),
             $variables->values(),
             $this->value
         );
     }
 
+    private function resolveNestedVariables(Variables $variables): Variables
+    {
+        $target = clone $variables;
+        foreach ($variables as $key => $value) {
+            if ($value instanceof self) {
+                $otherVariables = clone $variables;
+                unset($otherVariables[$key]);
+                $target[$key] = $value->apply($otherVariables);
+            }
+        }
+        return $target;
+    }
+
     private function assertVariableNames(Variables $variables): void
     {
         $missingVariableNames = array_diff($this->variableNames, $variables->keys());
@@ -89,7 +117,7 @@ class VariableValue
         }
     }
 
-    private function extractVariableNames(string $value): array
+    private static function extractVariableNames(string $value): array
     {
         if (!preg_match_all('#\[\[(?P<variableName>[^\[\]]+)\]\]#', $value, $matches)) {
             return [];
@@ -97,8 +125,19 @@ class VariableValue
         return array_unique($matches['variableName']);
     }
 
-    private function wrap(string $item): string
+    private static function wrap(string $item): string
     {
         return '[[' . $item . ']]';
     }
+
+    private static function urlEncodeParams(string $value, string $prefix = '&'): string
+    {
+        $variableNames = self::extractVariableNames($value);
+        $variableItems = array_map([self::class, 'wrap'], $variableNames);
+        $substitutes = array_map(static fn(): string => bin2hex(random_bytes(20)), $variableNames);
+        $value = str_replace($variableItems, $substitutes, $value);
+        parse_str($value, $params);
+        $value = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
+        return $prefix . str_replace($substitutes, $variableItems, $value);
+    }
 }