diff --git a/core/lib/Drupal/Core/PathProcessor/InboundPathProcessorInterface.php b/core/lib/Drupal/Core/PathProcessor/InboundPathProcessorInterface.php
index ed9d187..255ac43 100644
--- a/core/lib/Drupal/Core/PathProcessor/InboundPathProcessorInterface.php
+++ b/core/lib/Drupal/Core/PathProcessor/InboundPathProcessorInterface.php
@@ -12,10 +12,17 @@
   /**
    * Processes the inbound path.
    *
+   * Implementations may make changes to the request object passed in but should
+   * avoid all other side effects. This method can be called to process requests
+   * other that the current request.
+   *
    * @param string $path
    *   The path to process, with a leading slash.
    * @param \Symfony\Component\HttpFoundation\Request $request
-   *   The HttpRequest object representing the current request.
+   *   The HttpRequest object representing the request to process. Note, if this
+   *   method is being called via the path_processor_manager service and is not
+   *   part of routing, then the current request object must be cloned before
+   *   being passed in.
    *
    * @return string
    *   The processed path.
diff --git a/core/modules/language/tests/src/Functional/LanguageUILanguageNegotiationTest.php b/core/modules/language/tests/src/Functional/LanguageUILanguageNegotiationTest.php
index 34f0c81..a58618f 100644
--- a/core/modules/language/tests/src/Functional/LanguageUILanguageNegotiationTest.php
+++ b/core/modules/language/tests/src/Functional/LanguageUILanguageNegotiationTest.php
@@ -2,7 +2,9 @@
 
 namespace Drupal\Tests\language\Functional;
 
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Url;
+use Drupal\file\Entity\File;
 use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationBrowser;
 use Drupal\language\Plugin\LanguageNegotiation\LanguageNegotiationSelected;
@@ -40,6 +42,13 @@
 class LanguageUILanguageNegotiationTest extends BrowserTestBase {
 
   /**
+   * The admin user for testing.
+   *
+   * @var \Drupal\user\Entity\User
+   */
+  protected $adminUser;
+
+  /**
    * Modules to enable.
    *
    * We marginally use interface translation functionality here, so need to use
@@ -53,8 +62,8 @@ class LanguageUILanguageNegotiationTest extends BrowserTestBase {
   protected function setUp() {
     parent::setUp();
 
-    $admin_user = $this->drupalCreateUser(['administer languages', 'translate interface', 'access administration pages', 'administer blocks']);
-    $this->drupalLogin($admin_user);
+    $this->adminUser = $this->drupalCreateUser(['administer languages', 'translate interface', 'access administration pages', 'administer blocks']);
+    $this->drupalLogin($this->adminUser);
   }
 
   /**
@@ -73,6 +82,17 @@ public function testUILanguageNegotiation() {
     // For setting browser language preference to some unknown.
     $http_header_blah = ["Accept-Language" => "blah;q=1"];
 
+    // Create a private file for testing accessible by the admin user.
+    drupal_mkdir($this->privateFilesDirectory . '/test');
+    $filepath = 'private://test/private-file-test.txt';
+    $contents = "file_put_contents() doesn't seem to appreciate empty strings so let's put in some data.";
+    file_put_contents($filepath, $contents);
+    $file = File::create([
+      'uri' => $filepath,
+      'uid' => $this->adminUser->id(),
+    ]);
+    $file->save();
+
     // Setup the site languages by installing two languages.
     // Set the default language in order for the translated string to be registered
     // into database when seen by t(). Without doing this, our target string
@@ -359,6 +379,13 @@ protected function doRunTest($test) {
     $this->drupalGet($test['path'], $test['path_options'], $test['http_header']);
     $this->assertText($test['expect'], $test['message']);
     $this->assertText(t('Language negotiation method: @name', ['@name' => $test['expected_method_id']]));
+
+    // Get the private file and ensure it is a 200. It is important to
+    // invalidate the router cache to ensure the routing system runs a full
+    // match.
+    Cache::invalidateTags(['route_match']);
+    $this->drupalGet('system/files/test/private-file-test.txt');
+    $this->assertResponse(200);
   }
 
   /**
diff --git a/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php b/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
index c00509f..5618605 100644
--- a/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
+++ b/core/modules/user/src/Plugin/LanguageNegotiation/LanguageNegotiationUserAdmin.php
@@ -127,10 +127,14 @@ protected function isAdminPath(Request $request) {
       $route_match = $this->stackedRouteMatch->getRouteMatchFromRequest($request);
       if ($route_match && !$route_object = $route_match->getRouteObject()) {
         try {
+          // Some inbound path processors make changes to the request. Make a
+          // copy as we're not actually routing the request so we do not want to
+          // make changes.
+          $cloned_request = clone $request;
           // Process the path as an inbound path. This will remove any language
           // prefixes and other path components that inbound processing would
           // clear out, so we can attempt to load the route clearly.
-          $path = $this->pathProcessorManager->processInbound(urldecode(rtrim($request->getPathInfo(), '/')), $request);
+          $path = $this->pathProcessorManager->processInbound(urldecode(rtrim($cloned_request->getPathInfo(), '/')), $cloned_request);
           $attributes = $this->router->match($path);
         }
         catch (ResourceNotFoundException $e) {
