diff --git a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
index 6fc54a38c00f23ce78f265a8906462d2a5325714..b29ed6f4128095a1f76932d0e68be056c97b5d23 100644
--- a/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
+++ b/core/lib/Drupal/Core/EventSubscriber/FinishResponseSubscriber.php
@@ -12,7 +12,6 @@
 use Drupal\Core\Site\Settings;
 use Symfony\Component\HttpFoundation\Request;
 use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\HttpFoundation\StreamedResponse;
 use Symfony\Component\HttpKernel\Event\ResponseEvent;
 use Symfony\Component\HttpKernel\KernelEvents;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -306,14 +305,33 @@ protected function setExpiresNoCache(Response $response) {
    *
    * @param \Symfony\Component\HttpKernel\Event\ResponseEvent $event
    *   The event to process.
+   *
+   * @see \Symfony\Component\HttpFoundation\Response::prepare()
+   * @see https://www.rfc-editor.org/rfc/rfc9110.html#name-content-length
    */
   public function setContentLengthHeader(ResponseEvent $event): void {
     $response = $event->getResponse();
-    if ($response instanceof StreamedResponse) {
+
+    if ($response->isInformational() || $response->isEmpty()) {
+      return;
+    }
+
+    if ($response->headers->has('Transfer-Encoding')) {
+      return;
+    }
+
+    // Drupal cannot set the correct content length header when there is a
+    // server error.
+    if ($response->isServerError()) {
+      return;
+    }
+
+    $content = $response->getContent();
+    if ($content === FALSE) {
       return;
     }
 
-    $response->headers->set('Content-Length', strlen($response->getContent()), TRUE);
+    $response->headers->set('Content-Length', strlen($content), TRUE);
   }
 
   /**
diff --git a/core/tests/Drupal/Tests/Core/EventSubscriber/FinishResponserSubscriberTest.php b/core/tests/Drupal/Tests/Core/EventSubscriber/FinishResponserSubscriberTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..aefe20609c6bfc13792c9e60a93028c271588ba5
--- /dev/null
+++ b/core/tests/Drupal/Tests/Core/EventSubscriber/FinishResponserSubscriberTest.php
@@ -0,0 +1,108 @@
+<?php
+
+namespace Drupal\Tests\Core\EventSubscriber;
+
+use Drupal\Core\Cache\Context\CacheContextsManager;
+use Drupal\Core\EventSubscriber\FinishResponseSubscriber;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\PageCache\RequestPolicyInterface;
+use Drupal\Core\PageCache\ResponsePolicyInterface;
+use Drupal\Tests\UnitTestCase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\StreamedResponse;
+use Symfony\Component\HttpKernel\Event\ResponseEvent;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+
+/**
+ * @coversDefaultClass \Drupal\Core\EventSubscriber\FinishResponseSubscriber
+ * @group EventSubscriber
+ */
+class FinishResponserSubscriberTest extends UnitTestCase {
+
+  /**
+   * @covers ::setContentLengthHeader
+   * @dataProvider providerTestSetContentLengthHeader
+   */
+  public function testSetContentLengthHeader(false|int $expected_header, Response $response) {
+    $event_subscriber = new FinishResponseSubscriber(
+      $this->prophesize(LanguageManagerInterface::class)->reveal(),
+      $this->getConfigFactoryStub(),
+      $this->prophesize(RequestPolicyInterface::class)->reveal(),
+      $this->prophesize(ResponsePolicyInterface::class)->reveal(),
+      $this->prophesize(CacheContextsManager::class)->reveal()
+    );
+
+    $event = new ResponseEvent(
+      $this->prophesize(HttpKernelInterface::class)->reveal(),
+      $this->prophesize(Request::class)->reveal(),
+      HttpKernelInterface::MAIN_REQUEST,
+      $response
+    );
+
+    $event_subscriber->setContentLengthHeader($event);
+    if ($expected_header === FALSE) {
+      $this->assertFalse($event->getResponse()->headers->has('Content-Length'));
+    }
+    else {
+      $this->assertSame((string) $expected_header, $event->getResponse()->headers->get('Content-Length'));
+    }
+  }
+
+  public function providerTestSetContentLengthHeader() {
+    return [
+      'Informational' => [
+        FALSE,
+        new Response('', 101),
+      ],
+      '200 ok' => [
+        12,
+        new Response('Test content', 200),
+      ],
+      '204' => [
+        FALSE,
+        new Response('Test content', 204),
+      ],
+      '304' => [
+        FALSE,
+        new Response('Test content', 304),
+      ],
+      'Client error' => [
+        13,
+        new Response('Access denied', 403),
+      ],
+      'Server error' => [
+        FALSE,
+        new Response('Test content', 500),
+      ],
+      '200 with transfer-encoding' => [
+        FALSE,
+        new Response('Test content', 200, ['Transfer-Encoding' => 'Chunked']),
+      ],
+      '200 with FalseContentResponse' => [
+        FALSE,
+        new FalseContentResponse('Test content', 200),
+      ],
+      '200 with StreamedResponse' => [
+        FALSE,
+        new StreamedResponse(status: 200),
+      ],
+
+    ];
+  }
+
+}
+
+/**
+ * Response that returns FALSE from ::getContent().
+ */
+class FalseContentResponse extends Response {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getContent(): string|false {
+    return FALSE;
+  }
+
+}