diff --git a/core/modules/migrate_drupal_ui/src/Form/CredentialForm.php b/core/modules/migrate_drupal_ui/src/Form/CredentialForm.php
index cd767cc3d1d73c56fca61f07b650f5d97a09a983..deeebe5987a55a6acc24ba70b62a8f5a43ae2356 100644
--- a/core/modules/migrate_drupal_ui/src/Form/CredentialForm.php
+++ b/core/modules/migrate_drupal_ui/src/Form/CredentialForm.php
@@ -2,9 +2,12 @@
 
 namespace Drupal\migrate_drupal_ui\Form;
 
+use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\TempStore\PrivateTempStoreFactory;
+use GuzzleHttp\ClientInterface;
+use GuzzleHttp\Exception\TransferException;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
@@ -21,6 +24,20 @@ class CredentialForm extends MigrateUpgradeFormBase {
    */
   protected $renderer;
 
+  /**
+   * The HTTP client to fetch the files with.
+   *
+   * @var \GuzzleHttp\ClientInterface
+   */
+  protected $httpClient;
+
+  /**
+   * An array of error information.
+   *
+   * @var array
+   */
+  protected $errors = [];
+
   /**
    * CredentialForm constructor.
    *
@@ -28,10 +45,13 @@ class CredentialForm extends MigrateUpgradeFormBase {
    *   The renderer service.
    * @param \Drupal\Core\TempStore\PrivateTempStoreFactory $tempstore_private
    *   The private tempstore factory.
+   * @param \GuzzleHttp\ClientInterface $http_client
+   *   A Guzzle client object.
    */
-  public function __construct(RendererInterface $renderer, PrivateTempStoreFactory $tempstore_private) {
+  public function __construct(RendererInterface $renderer, PrivateTempStoreFactory $tempstore_private, ClientInterface $http_client) {
     parent::__construct($tempstore_private);
     $this->renderer = $renderer;
+    $this->httpClient = $http_client;
   }
 
   /**
@@ -40,7 +60,8 @@ public function __construct(RendererInterface $renderer, PrivateTempStoreFactory
   public static function create(ContainerInterface $container) {
     return new static(
       $container->get('renderer'),
-      $container->get('tempstore.private')
+      $container->get('tempstore.private'),
+      $container->get('http_client')
     );
   }
 
@@ -75,6 +96,11 @@ public function buildForm(array $form, FormStateInterface $form_state) {
 
     $default_options = [];
 
+    $form['help'] = [
+      '#type' => 'item',
+      '#description' => $this->t('Provide the information to access the Drupal site you want to upgrade. Files can be imported into the upgraded site as well.  See the <a href=":url">Upgrade documentation for more detailed instructions</a>.', [':url' => 'https://www.drupal.org/upgrade/migrate']),
+    ];
+
     $form['version'] = [
       '#type' => 'radios',
       '#default_value' => 7,
@@ -145,6 +171,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
           ':input[name="version"]' => ['value' => '6'],
         ],
       ],
+      '#element_validate' => ['::validatePaths'],
     ];
 
     $form['source']['source_base_path'] = [
@@ -156,6 +183,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
           ':input[name="version"]' => ['value' => '7'],
         ],
       ],
+      '#element_validate' => ['::validatePaths'],
     ];
 
     $form['source']['source_private_file_path'] = [
@@ -168,6 +196,7 @@ public function buildForm(array $form, FormStateInterface $form_state) {
           ':input[name="version"]' => ['value' => '7'],
         ],
       ],
+      '#element_validate' => ['::validatePaths'],
     ];
 
     return $form;
@@ -177,7 +206,6 @@ public function buildForm(array $form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function validateForm(array &$form, FormStateInterface $form_state) {
-
     // Retrieve the database driver from the form, use reflection to get the
     // namespace, and then construct a valid database array the same as in
     // settings.php.
@@ -194,35 +222,61 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
     // Validate the driver settings and just end here if we have any issues.
     if ($errors = $drivers[$driver]->validateDatabaseSettings($database)) {
       foreach ($errors as $name => $message) {
-        $form_state->setErrorByName($name, $message);
+        $this->errors[$name] = $message;
       }
-      return;
     }
-
-    try {
-      $connection = $this->getConnection($database);
-      $version = (string) $this->getLegacyDrupalVersion($connection);
-      if (!$version) {
-        $form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database does not contain a recognizable Drupal version.'));
+    else {
+      try {
+        $connection = $this->getConnection($database);
+        $version = (string) $this->getLegacyDrupalVersion($connection);
+        if (!$version) {
+          $this->errors[$database['driver'] . '][database'] = $this->t('Source database does not contain a recognizable Drupal version.');
+        }
+        elseif ($version !== (string) $form_state->getValue('version')) {
+          $this->errors['version'] = $this->t('Source database is Drupal version @version but version @selected was selected.',
+            [
+              '@version' => $version,
+              '@selected' => $form_state->getValue('version'),
+            ]);
+        }
+        else {
+          // Setup migrations and save form data to private store.
+          $this->setupMigrations($database, $form_state);
+        }
       }
-      elseif ($version !== (string) $form_state->getValue('version')) {
-        $form_state->setErrorByName($database['driver'] . '][0', $this->t('Source database is Drupal version @version but version @selected was selected.', [
-          '@version' => $version,
-          '@selected' => $form_state->getValue('version'),
-        ]));
+      catch (\Exception $e) {
+        $this->errors[$database['driver'] . '][database'] = $e->getMessage();
       }
-      else {
-        // Setup migrations and save form data to private store.
-        $this->setupMigrations($database, $form_state);
+    }
+
+    // Display all errors as a list of items.
+    if ($this->errors) {
+      $form_state->setError($form, $this->t('<h3>Resolve all issues below to continue the upgrade.</h3>'));
+      foreach ($this->errors as $name => $message) {
+        $form_state->setErrorByName($name, $message);
       }
     }
-    catch (\Exception $e) {
-      $error_message = [
-        '#title' => $this->t('Resolve the issue below to continue the upgrade.'),
-        '#theme' => 'item_list',
-        '#items' => [$e->getMessage()],
-      ];
-      $form_state->setErrorByName($database['driver'] . '][0', $this->renderer->renderPlain($error_message));
+  }
+
+  /**
+   * The #element_validate handler for the source path elements.
+   *
+   * Ensures that entered path can be read.
+   */
+  public function validatePaths($element, FormStateInterface $form_state) {
+    if ($source = $element['#value']) {
+      $msg = $this->t('Unable to read from @title.', ['@title' => $element['#title']]);
+      if (UrlHelper::isExternal($source)) {
+        try {
+          $this->httpClient->head($source);
+        }
+        catch (TransferException $e) {
+          $this->errors[$element['#name']] = $msg . ' ' . $e->getMessage();
+        }
+      }
+      elseif (!file_exists($source) || (!is_dir($source)) || (!is_readable($source))) {
+        $this->errors[$element['#name']] = $msg;
+      }
     }
   }
 
diff --git a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
index 22ec01c0ebd8b352a9c2bab9d83d5812987bfdef..bb822b9370ced47c21c935c93725af4136eb0fc9 100644
--- a/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
+++ b/core/modules/migrate_drupal_ui/tests/src/Functional/MigrateUpgradeExecuteTestBase.php
@@ -68,16 +68,35 @@ public function testMigrateUpgradeExecute() {
     // Ensure submitting the form with invalid database credentials gives us a
     // nice warning.
     $this->drupalPostForm(NULL, [$driver . '[database]' => 'wrong'] + $edits, t('Review upgrade'));
-    $session->pageTextContains('Resolve the issue below to continue the upgrade.');
+    $session->pageTextContains('Resolve all issues below to continue the upgrade.');
 
     $this->drupalPostForm(NULL, $edits, t('Review upgrade'));
     // Ensure we get errors about missing modules.
-    $session->pageTextContains(t('Resolve the issue below to continue the upgrade'));
+    $session->pageTextContains(t('Resolve all issues below to continue the upgrade.'));
     $session->pageTextContains(t('The no_source_module plugin must define the source_module property.'));
 
     // Uninstall the module causing the missing module error messages.
     $this->container->get('module_installer')->uninstall(['migration_provider_test'], TRUE);
 
+    // Test the file sources.
+    $this->drupalGet('/upgrade');
+    $this->drupalPostForm(NULL, [], t('Continue'));
+    if ($version == 6) {
+      $paths['d6_source_base_path'] = DRUPAL_ROOT . '/wrong-path';
+    }
+    else {
+      $paths['source_base_path'] = 'https://example.com/wrong-path';
+      $paths['source_private_file_path'] = DRUPAL_ROOT . '/wrong-path';
+    }
+    $this->drupalPostForm(NULL, $paths + $edits, t('Review upgrade'));
+    if ($version == 6) {
+      $session->responseContains('Unable to read from Files directory.');
+    }
+    else {
+      $session->responseContains('Unable to read from Public files directory.');
+      $session->responseContains('Unable to read from Private file directory.');
+    }
+
     // Restart the upgrade process.
     $this->drupalGet('/upgrade');
     $session->responseContains('Upgrade a site by importing its files and the data from its database into a clean and empty new install of Drupal 8.');