diff --git a/core/lib/Drupal/Core/DrupalKernel.php b/core/lib/Drupal/Core/DrupalKernel.php
index dd67a2b5416f6c604b6e1062c72926107af8aff5..d778693888f699508fbc44c9cab1b182a668bf5f 100644
--- a/core/lib/Drupal/Core/DrupalKernel.php
+++ b/core/lib/Drupal/Core/DrupalKernel.php
@@ -28,6 +28,8 @@
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
 use Symfony\Component\HttpKernel\TerminableInterface;
@@ -582,6 +584,11 @@ public function preHandle(Request $request) {
       (bool) Settings::get(RequestSanitizer::SANITIZE_LOG, FALSE)
     );
 
+    // Ensure that there is a session on every request.
+    if (!$request->hasSession()) {
+      $this->initializeEphemeralSession($request);
+    }
+
     $this->loadLegacyIncludes();
 
     // Load all enabled modules.
@@ -1638,4 +1645,23 @@ protected function getInstallProfile() {
     return $config['profile'] ?? NULL;
   }
 
+  /**
+   * Initializes a session backed by in-memory store and puts it on the request.
+   *
+   * A simple in-memory store is sufficient for command line tools and tests.
+   * Web requests will be processed by the session middleware where the mock
+   * session is replaced by a session object backed with persistent storage and
+   * a real session handler.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request.
+   *
+   * @see \Drupal\Core\StackMiddleware\Session::handle()
+   */
+  protected function initializeEphemeralSession(Request $request): void {
+    $session = new Session(new MockArraySessionStorage());
+    $session->start();
+    $request->setSession($session);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/StackMiddleware/Session.php b/core/lib/Drupal/Core/StackMiddleware/Session.php
index d9da60ac602518ae5a71d66f1d7df673307d0363..94841e1508dde7a62b2ebb85a9a5406b3600f2ff 100644
--- a/core/lib/Drupal/Core/StackMiddleware/Session.php
+++ b/core/lib/Drupal/Core/StackMiddleware/Session.php
@@ -49,19 +49,42 @@ public function __construct(HttpKernelInterface $http_kernel, $service_name = 's
    * {@inheritdoc}
    */
   public function handle(Request $request, $type = self::MAIN_REQUEST, $catch = TRUE): Response {
+    // Initialize and start a session for web requests. Command line tools and
+    // the parent site in functional tests must continue to use the ephemeral
+    // session initialized and started in DrupalKernel::preHandle().
     if ($type === self::MAIN_REQUEST && PHP_SAPI !== 'cli') {
-      $session = $this->container->get($this->sessionServiceName);
-      $session->start();
-      $request->setSession($session);
+      $this->initializePersistentSession($request);
     }
 
     $result = $this->httpKernel->handle($request, $type, $catch);
 
-    if ($type === self::MAIN_REQUEST && $request->hasSession()) {
+    if ($type === self::MAIN_REQUEST && PHP_SAPI !== 'cli' && $request->hasSession()) {
       $request->getSession()->save();
     }
 
     return $result;
   }
 
+  /**
+   * Initializes a session backed by persistent store and puts it on the request.
+   *
+   * Sessions for web requests need to be backed by a persistent session store
+   * and a real session handler (responsible for session cookie management).
+   * In contrast, a simple in-memory store is sufficient for command line tools
+   * and tests. Hence, the persistent session should only ever be placed on web
+   * requests while command line tools and the parent site in functional tests
+   * must continue to use the ephemeral session initialized in
+   * DrupalKernel::preHandle().
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request.
+   *
+   * @see \Drupal\Core\DrupalKernel::preHandle()
+   */
+  protected function initializePersistentSession(Request $request): void {
+    $session = $this->container->get($this->sessionServiceName);
+    $session->start();
+    $request->setSession($session);
+  }
+
 }
diff --git a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
index 2e7083ff86f076e0a42e9a9c215927e19c27b915..737f1ef247e7e7093a496ceb046d43160e765c56 100644
--- a/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
+++ b/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -23,6 +23,8 @@
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\Yaml\Yaml as SymfonyYaml;
 use Drupal\Core\Routing\RouteObjectInterface;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -210,10 +212,6 @@ protected function setContainerParameter($name, $value) {
   protected function rebuildContainer() {
     // Rebuild the kernel and bring it back to a fully bootstrapped state.
     $this->container = $this->kernel->rebuildContainer();
-
-    // Make sure the URL generator has a request object, otherwise calls to
-    // $this->drupalGet() will fail.
-    $this->prepareRequestForGenerator();
   }
 
   /**
@@ -254,6 +252,7 @@ protected function resetAll() {
    */
   protected function prepareRequestForGenerator($clean_urls = TRUE, $override_server_vars = []) {
     $request = Request::createFromGlobals();
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $base_path = $request->getBasePath();
     if ($clean_urls) {
       $request_path = $base_path ? $base_path . '/user' : 'user';
@@ -265,6 +264,7 @@ protected function prepareRequestForGenerator($clean_urls = TRUE, $override_serv
     $server = array_merge($request->server->all(), $override_server_vars);
 
     $request = Request::create($request_path, 'GET', [], [], [], $server);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     // Ensure the request time is REQUEST_TIME to ensure that API calls
     // in the test use the right timestamp.
     $request->server->set('REQUEST_TIME', REQUEST_TIME);
diff --git a/core/modules/book/tests/src/Kernel/BookMultilingualTest.php b/core/modules/book/tests/src/Kernel/BookMultilingualTest.php
index fbdfc3d8499a3251ae69250744b2b7329923b413..7c2ead6bc72e295439ca08f2a24fc020ec7cd3d3 100644
--- a/core/modules/book/tests/src/Kernel/BookMultilingualTest.php
+++ b/core/modules/book/tests/src/Kernel/BookMultilingualTest.php
@@ -14,6 +14,8 @@
 use Drupal\Tests\user\Traits\UserCreationTrait;
 use Drupal\user\Plugin\LanguageNegotiation\LanguageNegotiationUser;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -271,7 +273,9 @@ public function langcodesProvider() {
    *   is used instead of the content language.
    */
   protected function setCurrentLanguage(string $langcode): void {
-    \Drupal::requestStack()->push(Request::create("http://$langcode.book.test.domain/"));
+    $request = Request::create("http://$langcode.book.test.domain/");
+    $request->setSession(new Session(new MockArraySessionStorage()));
+    \Drupal::requestStack()->push($request);
     $language_manager = $this->container->get('language_manager');
     $language_manager->reset();
     $current_user = \Drupal::currentUser();
diff --git a/core/modules/comment/tests/src/Kernel/CommentHostnameTest.php b/core/modules/comment/tests/src/Kernel/CommentHostnameTest.php
index a056c086de7df3fefed834f477dcd86caefa9e91..7099c6d935363327b4488034e57ea6b9b6cd3ff0 100644
--- a/core/modules/comment/tests/src/Kernel/CommentHostnameTest.php
+++ b/core/modules/comment/tests/src/Kernel/CommentHostnameTest.php
@@ -6,6 +6,8 @@
 use Drupal\comment\Entity\CommentType;
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests the hostname base field.
@@ -29,6 +31,7 @@ class CommentHostnameTest extends KernelTestBase {
   public function testGetDefaultHostname() {
     // Create a fake request to be used for testing.
     $request = Request::create('/', 'GET', [], [], [], ['REMOTE_ADDR' => '203.0.113.1']);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     /** @var \Symfony\Component\HttpFoundation\RequestStack $stack */
     $stack = $this->container->get('request_stack');
     $stack->push($request);
diff --git a/core/modules/file/tests/src/Kernel/RequirementsTest.php b/core/modules/file/tests/src/Kernel/RequirementsTest.php
index 4d472644dc4bda2aaebb6d9bb305b93b342bee79..224616e089b8bc57714db9a0c42da563953b9a81 100644
--- a/core/modules/file/tests/src/Kernel/RequirementsTest.php
+++ b/core/modules/file/tests/src/Kernel/RequirementsTest.php
@@ -7,6 +7,8 @@
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests the file requirements.
@@ -69,6 +71,7 @@ public function testUploadRequirements(): void {
    */
   private function setServerSoftware(?string $software): void {
     $request = new Request();
+    $request->setSession(new Session(new MockArraySessionStorage()));
     if (is_string($software)) {
       $request->server->set('SERVER_SOFTWARE', $software);
     }
diff --git a/core/modules/language/tests/src/Functional/LanguageNegotiationContentEntityTest.php b/core/modules/language/tests/src/Functional/LanguageNegotiationContentEntityTest.php
index d13b923e3b72499751f72fccefd637aca131a60c..d74a1def3940d8c50563c10bc44a0ef8f06239a3 100644
--- a/core/modules/language/tests/src/Functional/LanguageNegotiationContentEntityTest.php
+++ b/core/modules/language/tests/src/Functional/LanguageNegotiationContentEntityTest.php
@@ -10,6 +10,8 @@
 use Drupal\Tests\BrowserTestBase;
 use Drupal\Core\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -185,6 +187,7 @@ protected function setCurrentRequestForRoute($path, $route_name) {
     $request = Request::create($path);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, $route_name);
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route($path));
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container->get('request_stack')->push($request);
   }
 
diff --git a/core/modules/language/tests/src/Functional/LanguageUILanguageNegotiationTest.php b/core/modules/language/tests/src/Functional/LanguageUILanguageNegotiationTest.php
index 7a635e1140768bcd58d2c59fa5ba1a9ddca93e9e..46f518b2194af854bcb5d46b69bbf8f0ace9ac5d 100644
--- a/core/modules/language/tests/src/Functional/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/tests/src/Functional/LanguageUILanguageNegotiationTest.php
@@ -19,6 +19,8 @@
 use Symfony\Component\HttpFoundation\Request;
 use Drupal\language\LanguageNegotiatorInterface;
 use Drupal\block\Entity\Block;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests the language UI for language switching.
@@ -564,6 +566,7 @@ public function testLanguageDomain() {
 
     // Test HTTPS via current URL scheme.
     $request = Request::create('', 'GET', [], [], [], ['HTTPS' => 'on']);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container->get('request_stack')->push($request);
     $italian_url = Url::fromRoute('system.admin', [], ['language' => $languages['it']])->toString();
     $correct_link = 'https://' . $link;
diff --git a/core/modules/language/tests/src/Kernel/EntityUrlLanguageTest.php b/core/modules/language/tests/src/Kernel/EntityUrlLanguageTest.php
index 58ccffc612e74733a035374074b31b583fc42d84..44505aac764d88617d3acc057b3c4bb5ff3dc45f 100644
--- a/core/modules/language/tests/src/Kernel/EntityUrlLanguageTest.php
+++ b/core/modules/language/tests/src/Kernel/EntityUrlLanguageTest.php
@@ -9,6 +9,8 @@
 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationUrl;
 use Drupal\Core\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -132,6 +134,7 @@ protected function setCurrentRequestForRoute($path, $route_name) {
     $request = Request::create($path);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, $route_name);
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route($path));
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container->get('request_stack')->push($request);
   }
 
diff --git a/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php b/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php
index bc1288972936ef9118ffbc0292813fb208e79852..fd37d6720ea42345400c870e9047f8589b2f6228 100644
--- a/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php
+++ b/core/modules/menu_link_content/tests/src/Kernel/MenuLinkContentCacheabilityBubblingTest.php
@@ -12,6 +12,8 @@
 use Drupal\user\Entity\User;
 use Drupal\Core\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -62,6 +64,7 @@ public function testOutboundPathAndRouteProcessing() {
     $request = Request::create('/');
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<front>');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $request_stack->push($request);
     $request_context->fromRequest($request);
 
diff --git a/core/modules/rest/tests/src/Functional/Views/StyleSerializerTest.php b/core/modules/rest/tests/src/Functional/Views/StyleSerializerTest.php
index 7c72ea90ed2d57d718b68fe176b96e25594fca68..3e10fe98bfcafa3e23ca2c64585e0675aa8c4338 100644
--- a/core/modules/rest/tests/src/Functional/Views/StyleSerializerTest.php
+++ b/core/modules/rest/tests/src/Functional/Views/StyleSerializerTest.php
@@ -16,6 +16,8 @@
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\Views;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests the serializer style plugin.
@@ -594,6 +596,7 @@ public function testLivePreview() {
     // We set up a request so it looks like a request in the live preview.
     $request = new Request();
     $request->query->add([MainContentViewSubscriber::WRAPPER_FORMAT => 'drupal_ajax']);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
     $request_stack = \Drupal::service('request_stack');
     $request_stack->push($request);
diff --git a/core/modules/syslog/tests/src/Kernel/SyslogTest.php b/core/modules/syslog/tests/src/Kernel/SyslogTest.php
index 14137c73efae5fccd67eca5908bccb5e3fed8f32..987f6bef6ec635b5f22640d44cab6d1687aeca4d 100644
--- a/core/modules/syslog/tests/src/Kernel/SyslogTest.php
+++ b/core/modules/syslog/tests/src/Kernel/SyslogTest.php
@@ -4,6 +4,8 @@
 
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Test syslog logger functionality.
@@ -30,6 +32,7 @@ public function testSyslogWriting() {
 
     $request = Request::create('/page-not-found', 'GET', [], [], [], ['REMOTE_ADDR' => '1.2.3.4']);
     $request->headers->set('Referer', 'other-site');
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::requestStack()->push($request);
 
     $user = $this->getMockBuilder('Drupal\Core\Session\AccountInterface')->getMock();
diff --git a/core/modules/system/tests/src/Functional/Database/SelectPagerDefaultTest.php b/core/modules/system/tests/src/Functional/Database/SelectPagerDefaultTest.php
index 41aa5c3a830994e61b1aa48cce236b5809149cdd..67129d429c7c7a1bce764f2f226e0a3d8c7cde45 100644
--- a/core/modules/system/tests/src/Functional/Database/SelectPagerDefaultTest.php
+++ b/core/modules/system/tests/src/Functional/Database/SelectPagerDefaultTest.php
@@ -6,6 +6,8 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\Database\Query\PagerSelectExtender;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests the pager query select extender.
@@ -141,6 +143,7 @@ public function testElementNumbers() {
     $request->query->replace([
       'page' => '3, 2, 1, 0',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
 
     $connection = Database::getConnection();
diff --git a/core/modules/system/tests/src/Kernel/Block/SystemMenuBlockTest.php b/core/modules/system/tests/src/Kernel/Block/SystemMenuBlockTest.php
index a335d9648a563ac724b3c196418ddd86814747ab..a09d42b40219e3ae55eb9254ff0a7d97bed5fe24 100644
--- a/core/modules/system/tests/src/Kernel/Block/SystemMenuBlockTest.php
+++ b/core/modules/system/tests/src/Kernel/Block/SystemMenuBlockTest.php
@@ -11,6 +11,8 @@
 use Drupal\user\Entity\User;
 use Drupal\Core\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Routing\Route;
 use Symfony\Component\Routing\RouteCollection;
 
@@ -233,6 +235,7 @@ public function testConfigLevelDepth() {
     $request = new Request();
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'example3');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, $route);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container->get('request_stack')->push($request);
     // \Drupal\Core\Menu\MenuActiveTrail uses the cache collector pattern, which
     // includes static caching. Since this second scenario simulates a second
@@ -300,6 +303,7 @@ public function testConfigExpanded($active_route, $menu_block_level, $expected_i
     $request = new Request();
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, $active_route);
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, $route);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container->get('request_stack')->push($request);
 
     $block_build = $block->build();
diff --git a/core/modules/system/tests/src/Kernel/Theme/TwigIncludeTest.php b/core/modules/system/tests/src/Kernel/Theme/TwigIncludeTest.php
index 78298c5044d427e3d0eb4f71c9055c834f94ae98..2abfc8f1708cf7c00a619829f60a8a0812da8a73 100644
--- a/core/modules/system/tests/src/Kernel/Theme/TwigIncludeTest.php
+++ b/core/modules/system/tests/src/Kernel/Theme/TwigIncludeTest.php
@@ -68,8 +68,10 @@ public function testTemplateInclusion(): void {
     $twig_config = $this->container->getParameter('twig.config');
     $twig_config['allowed_file_extensions'][] = 'sql';
     $this->twigConfig = $twig_config;
-    $this->container->get('kernel')->shutdown();
-    $this->container->get('kernel')->boot();
+    // @todo This used to call shutdown() and boot(). rebuildContainer() is
+    // needed until we stop pushing the request twice and only popping it once.
+    // @see https://www.drupal.org/i/2613044
+    $this->container->get('kernel')->rebuildContainer();
     /** @var \Drupal\Core\Template\Loader\FilesystemLoader $loader */
     $loader = \Drupal::service('twig.loader.filesystem');
     $source = $loader->getSourceContext('@__main__\/core/tests/fixtures/files/sql-2.sql');
@@ -80,8 +82,10 @@ public function testTemplateInclusion(): void {
     $this->assertSame(['css', 'html', 'js', 'svg', 'twig', 'sql'], \Drupal::getContainer()->getParameter('twig.config')['allowed_file_extensions']);
     unset($twig_config['allowed_file_extensions']);
     $this->twigConfig = $twig_config;
-    $this->container->get('kernel')->shutdown();
-    $this->container->get('kernel')->boot();
+    // @todo This used to call shutdown() and boot(). rebuildContainer() is
+    // needed until we stop pushing the request twice and only popping it once.
+    // @see https://www.drupal.org/i/2613044
+    $this->container->get('kernel')->rebuildContainer();
     $this->assertArrayNotHasKey('allowed_file_extensions', \Drupal::getContainer()->getParameter('twig.config'));
     /** @var \Drupal\Core\Template\Loader\FilesystemLoader $loader */
     $loader = \Drupal::service('twig.loader.filesystem');
@@ -108,8 +112,10 @@ public function testTemplateInclusion(): void {
     // Allow files with no extension.
     $twig_config['allowed_file_extensions'] = ['twig', ''];
     $this->twigConfig = $twig_config;
-    $this->container->get('kernel')->shutdown();
-    $this->container->get('kernel')->boot();
+    // @todo This used to call shutdown() and boot(). rebuildContainer() is
+    // needed until we stop pushing the request twice and only popping it once.
+    // @see https://www.drupal.org/i/2613044
+    $this->container->get('kernel')->rebuildContainer();
     /** @var \Drupal\Core\Template\Loader\FilesystemLoader $loader */
     $loader = \Drupal::service('twig.loader.filesystem');
     $source = $loader->getSourceContext('@__main__\/' . $this->siteDirectory . '/test_file');
diff --git a/core/modules/system/tests/src/Kernel/Token/TokenReplaceKernelTest.php b/core/modules/system/tests/src/Kernel/Token/TokenReplaceKernelTest.php
index 516e3bd40c3806109a3c06a1569b4d946ecc0b1f..802190359b4c89b089f2702d5c9ce0109cc5403c 100644
--- a/core/modules/system/tests/src/Kernel/Token/TokenReplaceKernelTest.php
+++ b/core/modules/system/tests/src/Kernel/Token/TokenReplaceKernelTest.php
@@ -7,6 +7,8 @@
 use Drupal\Component\Utility\Xss;
 use Drupal\Core\Render\BubbleableMetadata;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests token replacement.
@@ -137,6 +139,7 @@ public function testSystemSiteTokenReplacement() {
       'SERVER_NAME' => 'http://localhost',
     ];
     $request = Request::create('/subdir/', 'GET', [], [], [], $server);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $request->server->add($server);
     $request_stack->push($request);
     $bubbleable_metadata = new BubbleableMetadata();
diff --git a/core/modules/views/src/Tests/AssertViewsCacheTagsTrait.php b/core/modules/views/src/Tests/AssertViewsCacheTagsTrait.php
index 897290b2877861ecf863f53737800ca220cfe822..d41a6dea939cd1a0fa4eb6325e3943231997ebab 100644
--- a/core/modules/views/src/Tests/AssertViewsCacheTagsTrait.php
+++ b/core/modules/views/src/Tests/AssertViewsCacheTagsTrait.php
@@ -6,6 +6,8 @@
 use Drupal\views\Plugin\views\display\DisplayPluginBase;
 use Drupal\views\ViewExecutable;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 trait AssertViewsCacheTagsTrait {
 
@@ -43,6 +45,7 @@ protected function assertViewsCacheTags(ViewExecutable $view, $expected_results_
     $request_stack = \Drupal::service('request_stack');
     $request = Request::createFromGlobals();
     $request->server->set('REQUEST_TIME', REQUEST_TIME);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $view->setRequest($request);
     $request_stack->push($request);
     $renderer->renderRoot($build);
@@ -123,6 +126,7 @@ protected function assertViewsCacheTagsFromStaticRenderArray(ViewExecutable $vie
     $request_stack = \Drupal::service('request_stack');
     $request = new Request();
     $request->server->set('REQUEST_TIME', REQUEST_TIME);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $request_stack->push($request);
     $renderer->renderRoot($build);
 
diff --git a/core/modules/views/tests/src/Kernel/Handler/AreaDisplayLinkTest.php b/core/modules/views/tests/src/Kernel/Handler/AreaDisplayLinkTest.php
index e3bbdfa5681350ec5b3a0356a713451494309eba..87a1afea80028905a5707b7e8de5fe8825281a67 100644
--- a/core/modules/views/tests/src/Kernel/Handler/AreaDisplayLinkTest.php
+++ b/core/modules/views/tests/src/Kernel/Handler/AreaDisplayLinkTest.php
@@ -15,6 +15,8 @@
 use Psr\Log\LoggerInterface;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests the core views_handler_area_display_link handler.
@@ -148,8 +150,7 @@ public function testAreaDisplayLink() {
 
     // Assert some special request parameters are filtered from the display
     // links.
-    $request_stack = new RequestStack();
-    $request_stack->push(Request::create('page_1', 'GET', [
+    $request = Request::create('page_1', 'GET', [
       'name' => 'John',
       'sort_by' => 'created',
       'sort_order' => 'ASC',
@@ -166,7 +167,10 @@ public function testAreaDisplayLink() {
       AjaxResponseSubscriber::AJAX_REQUEST_PARAMETER => 1,
       FormBuilderInterface::AJAX_FORM_REQUEST => 1,
       MainContentViewSubscriber::WRAPPER_FORMAT => 1,
-    ]));
+    ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
+    $request_stack = new RequestStack();
+    $request_stack->push($request);
     $this->container->set('request_stack', $request_stack);
     $view->destroy();
     $view->setDisplay('page_1');
diff --git a/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php b/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php
index e83b425dc42cabee039fa79d966d936c614623e0..f0035f4b1f4e574022d2e1370526f4141c6cd661 100644
--- a/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php
+++ b/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php
@@ -11,6 +11,7 @@
 use Drupal\Tests\Traits\Core\CronRunTrait;
 use Drupal\user\Entity\Role;
 use PHPUnit\Framework\ExpectationFailedException;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * Tests BrowserTestBase functionality.
@@ -521,6 +522,30 @@ public function testHtkey() {
     $this->assertSession()->statusCodeEquals(403);
   }
 
+  /**
+   * Tests that a usable session is on the request in test-runner.
+   */
+  public function testSessionOnRequest(): void {
+    /** @var \Symfony\Component\HttpFoundation\Session\Session $session */
+    $session = $this->container->get('request_stack')->getSession();
+
+    $session->set('some-val', 'do-not-cleanup');
+    $this->assertEquals('do-not-cleanup', $session->get('some-val'));
+
+    $session->set('some-other-val', 'do-cleanup');
+    $this->assertEquals('do-cleanup', $session->remove('some-other-val'));
+  }
+
+  /**
+   * Tests deprecation of modified request stack lacking a session.
+   *
+   * @group legacy
+   */
+  public function testDeprecatedSessionMissing(): void {
+    $this->expectDeprecation('Pushing requests without a session onto the request_stack is deprecated in drupal:10.3.0 and an error will be thrown from drupal:11.0.0. See https://www.drupal.org/node/3337193');
+    $this->container->get('request_stack')->push(Request::create('/'));
+  }
+
   /**
    * Tests that deprecation headers do not get duplicated.
    *
diff --git a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
index 7cd1ae5682cd5016a93c91d5912a1a786dad98f1..52c226c93ea38807acc65e4066f90f43fd40ca70 100644
--- a/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
+++ b/core/tests/Drupal/FunctionalTests/Installer/InstallerTestBase.php
@@ -15,6 +15,8 @@
 use Symfony\Component\DependencyInjection\Reference;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Base class for testing the interactive installer.
@@ -118,6 +120,7 @@ public function installDrupal() {
     // server information so that XDebug works.
     // @see install_begin_request()
     $request = Request::create($GLOBALS['base_url'] . '/core/install.php', 'GET', [], $_COOKIE, [], $_SERVER);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container = new ContainerBuilder();
     $request_stack = new RequestStack();
     $request_stack->push($request);
diff --git a/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php b/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php
index 42ff9e293aa0a46a73b0bdfd86b185d53ab85098..f941802c1434ea989fee92898cc5d5b8cf512d31 100644
--- a/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Entity/EntityQueryTest.php
@@ -13,6 +13,8 @@
 use Drupal\taxonomy\Entity\Vocabulary;
 use Drupal\Tests\field\Traits\EntityReferenceFieldCreationTrait;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 // cspell:ignore merhaba siema xsiemax
 
@@ -464,6 +466,7 @@ public function testSort() {
     $request->query->replace([
       'page' => '0,2',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $this->queryResults = $this->storage
       ->getQuery()
@@ -500,6 +503,7 @@ public function testTableSort() {
       'sort' => 'asc',
       'order' => 'Type',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
 
     $header = [
diff --git a/core/tests/Drupal/KernelTests/Core/File/FileUrlGeneratorTest.php b/core/tests/Drupal/KernelTests/Core/File/FileUrlGeneratorTest.php
index a4a004c825f765743e78319a092b74def07e7d07..5359ee3fc56aa50611fb336dc2cff013663650d1 100644
--- a/core/tests/Drupal/KernelTests/Core/File/FileUrlGeneratorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/File/FileUrlGeneratorTest.php
@@ -4,6 +4,8 @@
 
 use Drupal\Core\File\Exception\InvalidStreamWrapperException;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * @coversDefaultClass \Drupal\Core\File\FileUrlGenerator
@@ -154,6 +156,7 @@ public function testRelativeFileURL() {
 
     // Create a mock Request for transformRelative().
     $request = Request::create($GLOBALS['base_url']);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container->get('request_stack')->push($request);
     \Drupal::setContainer($this->container);
 
@@ -183,6 +186,7 @@ public function testGenerateURI($filepath, $expected) {
 
     // Create a mock Request for transformRelative().
     $request = Request::create($GLOBALS['base_url']);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container->get('request_stack')->push($request);
     \Drupal::setContainer($this->container);
 
@@ -200,6 +204,7 @@ public function testGenerateURIWithSchema() {
 
     // Create a mock Request for transformRelative().
     $request = Request::create($GLOBALS['base_url']);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container->get('request_stack')->push($request);
     \Drupal::setContainer($this->container);
 
diff --git a/core/tests/Drupal/KernelTests/Core/File/UrlTransformRelativeTest.php b/core/tests/Drupal/KernelTests/Core/File/UrlTransformRelativeTest.php
index 4a4d7e5a42b3195bb1fd9ed68e5c99ac1d77fdd4..c24bd75e3f5451631e7617110951fc33fd828c52 100644
--- a/core/tests/Drupal/KernelTests/Core/File/UrlTransformRelativeTest.php
+++ b/core/tests/Drupal/KernelTests/Core/File/UrlTransformRelativeTest.php
@@ -4,6 +4,8 @@
 
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests URL transform to relative.
@@ -35,6 +37,7 @@ public function testFileUrlTransformRelative($host, $port, $https, $base_path, $
     $_SERVER['HTTPS'] = $https;
 
     $request = Request::createFromGlobals();
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::requestStack()->push($request);
 
     $this->assertSame($expected, \Drupal::service('file_url_generator')->transformRelative($url, $root_relative));
diff --git a/core/tests/Drupal/KernelTests/Core/Form/ExternalFormUrlTest.php b/core/tests/Drupal/KernelTests/Core/Form/ExternalFormUrlTest.php
index b2486202890bd8b5da6c86f3aad5857839a3f66a..caa39c1cb722f6cfd499d940f2c87d20a590ba01 100644
--- a/core/tests/Drupal/KernelTests/Core/Form/ExternalFormUrlTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Form/ExternalFormUrlTest.php
@@ -7,6 +7,8 @@
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\user\Entity\User;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Ensures that form actions can't be tricked into sending to external URLs.
@@ -76,6 +78,7 @@ public function testActionUrlBehavior() {
     $request_stack->pop();
     $request_stack->pop();
     $request = Request::create($original_request->getSchemeAndHttpHost() . '//example.org');
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $request_stack->push($request);
 
     $form = \Drupal::formBuilder()->getForm($this);
@@ -91,6 +94,7 @@ public function testActionUrlBehavior() {
     $request_stack = \Drupal::service('request_stack');
     $original_request = $request_stack->pop();
     $request = Request::create($original_request->getSchemeAndHttpHost() . '/example.org');
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $request_stack->push($request);
 
     $form = \Drupal::formBuilder()->getForm($this);
diff --git a/core/tests/Drupal/KernelTests/Core/Form/FormActionXssTest.php b/core/tests/Drupal/KernelTests/Core/Form/FormActionXssTest.php
index fc67b354e94398dd3765a1963118728843423f44..2cf6e10b9091544b167e1adc6e641de51e59fffb 100644
--- a/core/tests/Drupal/KernelTests/Core/Form/FormActionXssTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Form/FormActionXssTest.php
@@ -7,6 +7,8 @@
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\user\Entity\User;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 // cspell:ignore attribute\'close
 
@@ -77,6 +79,7 @@ public function testFormActionXss() {
     $request_stack->pop();
     $request_stack->pop();
     $request = Request::create($original_request->getSchemeAndHttpHost() . '/test/"injected=\'attribute\'close="');
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $request_stack->push($request);
 
     $form = \Drupal::formBuilder()->getForm($this);
diff --git a/core/tests/Drupal/KernelTests/Core/Pager/PagerManagerTest.php b/core/tests/Drupal/KernelTests/Core/Pager/PagerManagerTest.php
index 3624b76e35e7543607433bd20273219e62d94b8c..11faa4aeb4ac0dd6cea30ae590ce7f89062507c1 100644
--- a/core/tests/Drupal/KernelTests/Core/Pager/PagerManagerTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Pager/PagerManagerTest.php
@@ -4,6 +4,8 @@
 
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * @group Pager
@@ -22,6 +24,7 @@ public function testGetUpdatedParameters() {
       'other' => 'arbitrary',
     ];
     $request = Request::create('http://example.com', 'GET', $test_parameters);
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
     $request_stack = $this->container->get('request_stack');
@@ -43,6 +46,7 @@ public function testGetUpdatedParameters() {
    */
   public function testFindPage() {
     $request = Request::create('http://example.com', 'GET', ['page' => '0,10']);
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
     $request_stack = $this->container->get('request_stack');
diff --git a/core/tests/Drupal/KernelTests/Core/Pager/RequestPagerTest.php b/core/tests/Drupal/KernelTests/Core/Pager/RequestPagerTest.php
index b21f75bc6f0c978c17bb67868ca3a9213e06c845..598f68dbafef80d04fa0b65514f0551c60a16ad6 100644
--- a/core/tests/Drupal/KernelTests/Core/Pager/RequestPagerTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Pager/RequestPagerTest.php
@@ -4,6 +4,8 @@
 
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * @group Pager
@@ -17,6 +19,7 @@ class RequestPagerTest extends KernelTestBase {
    */
   public function testFindPage() {
     $request = Request::create('http://example.com', 'GET', ['page' => '0,10']);
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
     $request_stack = $this->container->get('request_stack');
@@ -35,6 +38,7 @@ public function testGetQueryParameters() {
       'other' => 'arbitrary',
     ];
     $request = Request::create('http://example.com', 'GET', array_merge(['page' => '0,10'], $test_parameters));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     /** @var \Symfony\Component\HttpFoundation\RequestStack $request_stack */
     $request_stack = $this->container->get('request_stack');
diff --git a/core/tests/Drupal/KernelTests/Core/Path/PathValidatorTest.php b/core/tests/Drupal/KernelTests/Core/Path/PathValidatorTest.php
index 34a7bdf0006be545f3ceeb4124cd66c2f2f03c31..588fecae8c5be0fb7cac307e33523f3c0f4030f7 100644
--- a/core/tests/Drupal/KernelTests/Core/Path/PathValidatorTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Path/PathValidatorTest.php
@@ -55,10 +55,12 @@ public function testGetUrlIfValidWithoutAccessCheck() {
       FALSE,
     ];
     foreach ($methods as $method) {
+      /** @var \Symfony\Component\HttpFoundation\Request|null $request */
+      $request = NULL;
       if ($method === FALSE) {
         $request_stack = $this->container->get('request_stack');
         while ($request_stack->getCurrentRequest()) {
-          $request_stack->pop();
+          $request = $request_stack->pop();
         }
         $this->container->set('router.request_context', new RequestContext());
       }
@@ -69,6 +71,12 @@ public function testGetUrlIfValidWithoutAccessCheck() {
       $this->assertEquals($method, $requestContext->getMethod());
       $this->assertInstanceOf(Url::class, $url);
       $this->assertSame(['entity_test' => $entity->id()], $url->getRouteParameters());
+
+      if ($method === FALSE) {
+        // Restore main request.
+        $request_stack = $this->container->get('request_stack');
+        $request_stack->push($request);
+      }
     }
   }
 
diff --git a/core/tests/Drupal/KernelTests/Core/Plugin/Condition/RequestPathTest.php b/core/tests/Drupal/KernelTests/Core/Plugin/Condition/RequestPathTest.php
index 5eb8c624ceb1a166c04ff4098616b73a4b4940fe..8c8bc7942528467d4c5e20f3061e31f9f07143c3 100644
--- a/core/tests/Drupal/KernelTests/Core/Plugin/Condition/RequestPathTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Plugin/Condition/RequestPathTest.php
@@ -7,6 +7,8 @@
 use Drupal\system\Tests\Routing\MockAliasManager;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests system.module's request path condition.
@@ -83,6 +85,7 @@ public function testConditions() {
     $pages = "/my/pass/page\r\n/my/pass/page2\r\n/foo";
 
     $request = Request::create('/my/pass/page2');
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->requestStack->push($request);
 
     /** @var \Drupal\system\Plugin\Condition\RequestPath $condition */
diff --git a/core/tests/Drupal/KernelTests/Core/Plugin/Condition/ResponseStatusTest.php b/core/tests/Drupal/KernelTests/Core/Plugin/Condition/ResponseStatusTest.php
index 9f5690a6bf3ae6b5e007c1a8eac4852ca77128de..33c407508e75749ae01d91333d9be92308be73e6 100644
--- a/core/tests/Drupal/KernelTests/Core/Plugin/Condition/ResponseStatusTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Plugin/Condition/ResponseStatusTest.php
@@ -9,6 +9,8 @@
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\RequestStack;
 use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 
 /**
@@ -61,6 +63,7 @@ public function testConditions(array $status_codes, bool $negate, int $response_
       $request = new Request();
       $request->attributes->set('exception', new HttpException($response_code));
     }
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->requestStack->push($request);
 
     /** @var \Drupal\system\Plugin\Condition\ResponseStatus $condition */
diff --git a/core/tests/Drupal/KernelTests/Core/Render/Element/TableSortExtenderTest.php b/core/tests/Drupal/KernelTests/Core/Render/Element/TableSortExtenderTest.php
index b605b2111d45c1771a262e19208eeb19cff2ce76..c0bd45713a69627dd9190fecdcaef450f3ac24c2 100644
--- a/core/tests/Drupal/KernelTests/Core/Render/Element/TableSortExtenderTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Render/Element/TableSortExtenderTest.php
@@ -5,6 +5,8 @@
 use Drupal\Core\Utility\TableSort;
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests table sorting.
@@ -31,6 +33,7 @@ public function testTableSortInit() {
     ];
     $request = Request::createFromGlobals();
     $request->query->replace([]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $this->assertEquals($expected_ts, $ts, 'Simple table headers sorted correctly.');
@@ -43,6 +46,7 @@ public function testTableSortInit() {
       // headers are overridable.
       'order' => 'bar',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $this->assertEquals($expected_ts, $ts, 'Simple table headers plus non-overriding $_GET parameters sorted correctly.');
@@ -56,6 +60,7 @@ public function testTableSortInit() {
       // it in the links that it creates.
       'alpha' => 'beta',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $expected_ts['sort'] = 'desc';
     $expected_ts['query'] = ['alpha' => 'beta'];
@@ -83,6 +88,7 @@ public function testTableSortInit() {
     $request->query->replace([
       'order' => '2',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $expected_ts = [
@@ -101,6 +107,7 @@ public function testTableSortInit() {
       // exist.
       'order' => 'bar',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $expected_ts = [
@@ -121,6 +128,7 @@ public function testTableSortInit() {
       // it in the links that it creates.
       'alpha' => 'beta',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $expected_ts = [
       'name' => '1',
@@ -165,6 +173,7 @@ public function testTableSortInit() {
     $request->query->replace([
       'order' => '1',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $expected_ts = [
@@ -181,6 +190,7 @@ public function testTableSortInit() {
     $request->query->replace([
       'order' => '2',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $expected_ts = [
@@ -197,6 +207,7 @@ public function testTableSortInit() {
     $request->query->replace([
       'order' => '3',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $expected_ts = [
@@ -213,6 +224,7 @@ public function testTableSortInit() {
     $request->query->replace([
       'order' => '4',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $expected_ts = [
@@ -229,6 +241,7 @@ public function testTableSortInit() {
     $request->query->replace([
       'order' => '5',
     ]);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     \Drupal::getContainer()->get('request_stack')->push($request);
     $ts = TableSort::getContextFromRequest($headers, $request);
     $expected_ts = [
diff --git a/core/tests/Drupal/KernelTests/Core/RouteProcessor/RouteNoneTest.php b/core/tests/Drupal/KernelTests/Core/RouteProcessor/RouteNoneTest.php
index 21e62d9680aff06166951dadb0f03cfcacba1895..7e35066eebab1f321a650472536e48f9b605e6af 100644
--- a/core/tests/Drupal/KernelTests/Core/RouteProcessor/RouteNoneTest.php
+++ b/core/tests/Drupal/KernelTests/Core/RouteProcessor/RouteNoneTest.php
@@ -8,6 +8,8 @@
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\Core\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -59,6 +61,7 @@ public function testProcessOutbound() {
     $request = Request::create('/subdir', 'GET', [], [], [], $server);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<front>');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
@@ -76,6 +79,7 @@ public function testProcessOutbound() {
     $request = Request::create('/subdir/node/add', 'GET', [], [], [], $server);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'node.add');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/node/add'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
@@ -93,6 +97,7 @@ public function testProcessOutbound() {
     $request = Request::create('/', 'GET', [], [], [], $server);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<front>');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
@@ -110,6 +115,7 @@ public function testProcessOutbound() {
     $request = Request::create('/node/add', 'GET', [], [], [], $server);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'node.add');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/node/add'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
diff --git a/core/tests/Drupal/KernelTests/Core/RouteProcessor/RouteProcessorCurrentIntegrationTest.php b/core/tests/Drupal/KernelTests/Core/RouteProcessor/RouteProcessorCurrentIntegrationTest.php
index 1a99b00171f0be1fe443fc29b1eff70c931a0f16..1c585d8955dab3171cf3ac55cf2779de2a77f710 100644
--- a/core/tests/Drupal/KernelTests/Core/RouteProcessor/RouteProcessorCurrentIntegrationTest.php
+++ b/core/tests/Drupal/KernelTests/Core/RouteProcessor/RouteProcessorCurrentIntegrationTest.php
@@ -8,6 +8,8 @@
 use Drupal\KernelTests\KernelTestBase;
 use Drupal\Core\Routing\RouteObjectInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 use Symfony\Component\Routing\Route;
 
 /**
@@ -60,6 +62,7 @@ public function testProcessOutbound() {
     $request = Request::create('/subdir/', 'GET', [], [], [], $server);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<front>');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
@@ -75,6 +78,7 @@ public function testProcessOutbound() {
     $request = Request::create('/subdir/node/add', 'GET', [], [], [], $server);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'node.add');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/node/add'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
@@ -90,6 +94,7 @@ public function testProcessOutbound() {
     $request = Request::create('/', 'GET', [], [], [], $server);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, '<front>');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
@@ -105,6 +110,7 @@ public function testProcessOutbound() {
     $request = Request::create('/node/add', 'GET', [], [], [], $server);
     $request->attributes->set(RouteObjectInterface::ROUTE_NAME, 'node.add');
     $request->attributes->set(RouteObjectInterface::ROUTE_OBJECT, new Route('/node/add'));
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
@@ -119,6 +125,7 @@ public function testProcessOutbound() {
       'SERVER_NAME' => 'http://www.example.com',
     ];
     $request = Request::create('/invalid-path', 'GET', [], [], [], $server);
+    $request->setSession(new Session(new MockArraySessionStorage()));
 
     $request_stack->push($request);
     $request_context->fromRequest($request);
diff --git a/core/tests/Drupal/KernelTests/Core/StringTranslation/TranslationStringTest.php b/core/tests/Drupal/KernelTests/Core/StringTranslation/TranslationStringTest.php
index 77e37755f3c65cea503d9a921f7d558032a09c9a..b9544e8241278edd136b9192d05017dad81c9d7d 100644
--- a/core/tests/Drupal/KernelTests/Core/StringTranslation/TranslationStringTest.php
+++ b/core/tests/Drupal/KernelTests/Core/StringTranslation/TranslationStringTest.php
@@ -58,8 +58,10 @@ protected function rebootAndPrepareSettings() {
     // Reboot the container so that different services are injected and the new
     // settings are picked.
     $kernel = $this->container->get('kernel');
-    $kernel->shutdown();
-    $kernel->boot();
+    // @todo This used to call shutdown() and boot(). rebuildContainer() is
+    // needed until we stop pushing the request twice and only popping it once.
+    // @see https://www.drupal.org/i/2613044
+    $kernel->rebuildContainer();
     $settings = Settings::getAll();
     $settings['locale_custom_strings_de'] = ['' => ['Example @number' => 'Example @number translated']];
     // Recreate the settings static.
diff --git a/core/tests/Drupal/KernelTests/Core/Theme/ImageTest.php b/core/tests/Drupal/KernelTests/Core/Theme/ImageTest.php
index 509b6dea77f178f14db0842ef26f50de06db895a..c5b6336e5e8569d7486b27d0af9d4e92c9f57e56 100644
--- a/core/tests/Drupal/KernelTests/Core/Theme/ImageTest.php
+++ b/core/tests/Drupal/KernelTests/Core/Theme/ImageTest.php
@@ -4,6 +4,8 @@
 
 use Drupal\KernelTests\KernelTestBase;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Session\Session;
+use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage;
 
 /**
  * Tests built-in image theme functions.
@@ -43,6 +45,7 @@ protected function setUp(): void {
     // the Request containing the correct hostname. KernelTestBase doesn't set
     // it, so push another request onto the stack to ensure it's correct.
     $request = Request::create('/', 'GET', [], [], [], $_SERVER);
+    $request->setSession(new Session(new MockArraySessionStorage()));
     $this->container = \Drupal::service('kernel')->getContainer();
     $this->container->get('request_stack')->push($request);
 
diff --git a/core/tests/Drupal/KernelTests/KernelTestBase.php b/core/tests/Drupal/KernelTests/KernelTestBase.php
index 46b4d88018995b039576272e2ce8fb068244cd92..0a07f19c06431aadb581d34de1cb50c653d6134f 100644
--- a/core/tests/Drupal/KernelTests/KernelTestBase.php
+++ b/core/tests/Drupal/KernelTests/KernelTestBase.php
@@ -37,6 +37,7 @@
 use Symfony\Component\Routing\Route;
 use Symfony\Component\VarDumper\VarDumper;
 use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
+use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
 
 /**
  * Base class for functional integration tests.
@@ -667,6 +668,19 @@ protected function assertPostConditions(): void {
    * {@inheritdoc}
    */
   protected function tearDown(): void {
+    if ($this->container) {
+      // Clean up mock session started in DrupalKernel::preHandle().
+      try {
+        /** @var \Symfony\Component\HttpFoundation\Session\Session $session */
+        $session = $this->container->get('request_stack')->getSession();
+        $session->clear();
+        $session->save();
+      }
+      catch (SessionNotFoundException) {
+        @trigger_error('Pushing requests without a session onto the request_stack is deprecated in drupal:10.3.0 and an error will be thrown from drupal:11.0.0. See https://www.drupal.org/node/3337193', E_USER_DEPRECATED);
+      }
+    }
+
     // Destroy the testing kernel.
     if (isset($this->kernel)) {
       $this->kernel->shutdown();
diff --git a/core/tests/Drupal/KernelTests/KernelTestBaseTest.php b/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
index 689cf8b953e073e50b867d75b27aeb4502b7ccd4..be83c0a2672fc4118b979dcf78f1a5b7df31d94b 100644
--- a/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
+++ b/core/tests/Drupal/KernelTests/KernelTestBaseTest.php
@@ -11,6 +11,7 @@
 use org\bovigo\vfs\vfsStream;
 use org\bovigo\vfs\visitor\vfsStreamStructureVisitor;
 use PHPUnit\Framework\SkippedTestError;
+use Symfony\Component\HttpFoundation\Request;
 
 /**
  * @coversDefaultClass \Drupal\KernelTests\KernelTestBase
@@ -235,6 +236,34 @@ public function testBootKernel() {
     $this->assertEquals('public', \Drupal::config('system.file')->get('default_scheme'));
   }
 
+  /**
+   * Tests that a usable session is on the request.
+   *
+   * @covers ::bootKernel
+   */
+  public function testSessionOnRequest(): void {
+    /** @var \Symfony\Component\HttpFoundation\Session\Session $session */
+    $session = $this->container->get('request_stack')->getSession();
+
+    $session->set('some-val', 'do-not-cleanup');
+    $this->assertEquals('do-not-cleanup', $session->get('some-val'));
+
+    $session->set('some-other-val', 'do-cleanup');
+    $this->assertEquals('do-cleanup', $session->remove('some-other-val'));
+  }
+
+  /**
+   * Tests deprecation of modified request stack lacking a session.
+   *
+   * @covers ::tearDown
+   *
+   * @group legacy
+   */
+  public function testDeprecatedSessionMissing(): void {
+    $this->expectDeprecation('Pushing requests without a session onto the request_stack is deprecated in drupal:10.3.0 and an error will be thrown from drupal:11.0.0. See https://www.drupal.org/node/3337193');
+    $this->container->get('request_stack')->push(Request::create('/'));
+  }
+
   /**
    * Tests the assumption that local time is in 'Australia/Sydney'.
    */
diff --git a/core/tests/Drupal/Tests/BrowserTestBase.php b/core/tests/Drupal/Tests/BrowserTestBase.php
index 38b41f4163d198dd18d1a984ba31eab26f1c1c4f..082292646eefac000238680c92ef3b3215abba70 100644
--- a/core/tests/Drupal/Tests/BrowserTestBase.php
+++ b/core/tests/Drupal/Tests/BrowserTestBase.php
@@ -24,6 +24,7 @@
 use GuzzleHttp\Cookie\CookieJar;
 use PHPUnit\Framework\TestCase;
 use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
+use Symfony\Component\HttpFoundation\Exception\SessionNotFoundException;
 use Symfony\Component\VarDumper\VarDumper;
 
 /**
@@ -446,6 +447,19 @@ protected function cleanupEnvironment() {
   protected function tearDown(): void {
     parent::tearDown();
 
+    if ($this->container) {
+      // Cleanup mock session started in DrupalKernel::preHandle().
+      try {
+        /** @var \Symfony\Component\HttpFoundation\Session\Session $session */
+        $session = $this->container->get('request_stack')->getSession();
+        $session->clear();
+        $session->save();
+      }
+      catch (SessionNotFoundException) {
+        @trigger_error('Pushing requests without a session onto the request_stack is deprecated in drupal:10.3.0 and an error will be thrown from drupal:11.0.0. See https://www.drupal.org/node/3337193', E_USER_DEPRECATED);
+      }
+    }
+
     // Destroy the testing kernel.
     if (isset($this->kernel)) {
       $this->cleanupEnvironment();