diff --git a/aqt/exceptions.py b/aqt/exceptions.py
index f02f032..d56fd4f 100644
--- a/aqt/exceptions.py
+++ b/aqt/exceptions.py
@@ -18,14 +18,14 @@
 # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-from typing import Iterable
+from typing import List
 
 DOCS_CONFIG = "https://aqtinstall.readthedocs.io/en/stable/configuration.html#configuration"
 
 
 class AqtException(Exception):
     def __init__(self, *args, **kwargs):
-        self.suggested_action: Iterable[str] = kwargs.pop("suggested_action", [])
+        self.suggested_action: List[str] = kwargs.pop("suggested_action", [])
         self.should_show_help: bool = kwargs.pop("should_show_help", False)
         super(AqtException, self).__init__(*args, **kwargs)
 
@@ -40,6 +40,9 @@ class AqtException(Exception):
             ["* " + suggestion for suggestion in self.suggested_action]
         )
 
+    def append_suggested_follow_up(self, suggestions: List[str]):
+        self.suggested_action.extend(suggestions)
+
 
 class ArchiveDownloadError(AqtException):
     pass
diff --git a/aqt/metadata.py b/aqt/metadata.py
index 8c95cfc..7be73e6 100644
--- a/aqt/metadata.py
+++ b/aqt/metadata.py
@@ -450,7 +450,7 @@ class MetadataFactory:
         return arches
 
     def fetch_extensions(self, version: Version) -> List[str]:
-        versions_extensions = MetadataFactory.get_versions_extensions(
+        versions_extensions = self.get_versions_extensions(
             self.fetch_http(self.archive_id.to_url(), False), self.archive_id.category
         )
         filtered = filter(
@@ -467,7 +467,7 @@ class MetadataFactory:
         def get_version(ver_ext: Tuple[Version, str]):
             return ver_ext[0]
 
-        versions_extensions = MetadataFactory.get_versions_extensions(
+        versions_extensions = self.get_versions_extensions(
             self.fetch_http(self.archive_id.to_url(), False), self.archive_id.category
         )
         versions = sorted(filter(None, map(get_version, filter(filter_by, versions_extensions))))
@@ -479,7 +479,7 @@ class MetadataFactory:
 
     def fetch_tools(self) -> List[str]:
         html_doc = self.fetch_http(self.archive_id.to_url(), False)
-        return list(MetadataFactory.iterate_folders(html_doc, "tools"))
+        return list(self.iterate_folders(html_doc, "tools"))
 
     def fetch_tool_modules(self, tool_name: str) -> List[str]:
         tool_data = self._fetch_module_metadata(tool_name)
@@ -588,24 +588,32 @@ class MetadataFactory:
                         f"Connection to '{base_url}' failed. Retrying with fallback '{base_urls[i + 1]}'."
                     )
 
-    @staticmethod
-    def iterate_folders(html_doc: str, filter_category: str = "") -> Generator[str, None, None]:
+    def iterate_folders(self, html_doc: str, filter_category: str = "") -> Generator[str, None, None]:
         def table_row_to_folder(tr: bs4.element.Tag) -> str:
             try:
                 return tr.find_all("td")[1].a.contents[0].rstrip("/")
             except (AttributeError, IndexError):
                 return ""
 
-        soup: bs4.BeautifulSoup = bs4.BeautifulSoup(html_doc, "html.parser")
-        for row in soup.body.table.find_all("tr"):
-            content: str = table_row_to_folder(row)
-            if not content or content == "Parent Directory":
-                continue
-            if content.startswith(filter_category):
-                yield content
-
-    @staticmethod
-    def get_versions_extensions(html_doc: str, category: str) -> Iterator[Tuple[Optional[Version], str]]:
+        try:
+            soup: bs4.BeautifulSoup = bs4.BeautifulSoup(html_doc, "html.parser")
+            for row in soup.body.table.find_all("tr"):
+                content: str = table_row_to_folder(row)
+                if not content or content == "Parent Directory":
+                    continue
+                if content.startswith(filter_category):
+                    yield content
+        except Exception as e:
+            url = posixpath.join(Settings.baseurl, self.archive_id.to_url())
+            raise ArchiveConnectionError(
+                f"Failed to retrieve the expected HTML page at {url}",
+                suggested_action=[
+                    "Check your network connection.",
+                    f"Make sure that you can access {url} in your web browser.",
+                ],
+            ) from e
+
+    def get_versions_extensions(self, html_doc: str, category: str) -> Iterator[Tuple[Optional[Version], str]]:
         def folder_to_version_extension(folder: str) -> Tuple[Optional[Version], str]:
             components = folder.split("_", maxsplit=2)
             ext = "" if len(components) < 3 else components[2]
@@ -617,7 +625,7 @@ class MetadataFactory:
 
         return map(
             folder_to_version_extension,
-            MetadataFactory.iterate_folders(html_doc, category),
+            self.iterate_folders(html_doc, category),
         )
 
     @staticmethod
@@ -792,5 +800,5 @@ def show_list(meta: MetadataFactory):
         else:
             print(*output, sep=" ")
     except (ArchiveDownloadError, ArchiveConnectionError) as e:
-        e.suggested_action = suggested_follow_up(meta)
+        e.append_suggested_follow_up(suggested_follow_up(meta))
         raise e from e

diff --git a/tests/test_list.py b/tests/test_list.py
index 57e308e..de92e96 100644
--- a/tests/test_list.py
+++ b/tests/test_list.py
@@ -1,6 +1,7 @@
 import hashlib
 import json
 import os
+import posixpath
 import re
 import shutil
 import sys
@@ -178,6 +179,31 @@ def test_list_versions_tools(monkeypatch, spec_regex, os_name, target, in_file,
             assert f"{all_ver_for_spec}" == row
 
 
+@pytest.mark.parametrize(
+    "html_doc",
+    (
+        "<html><body>Login to my public WIFI network:<form>...</form></body></html>",
+        "<html>malformed-html/",
+    ),
+)
+def test_list_bad_html(monkeypatch, html_doc: str):
+    monkeypatch.setattr(MetadataFactory, "fetch_http", lambda *args, **kwargs: html_doc)
+    archive_id = ArchiveId("qt", "linux", "desktop")
+    expected_url = posixpath.join(Settings.baseurl, archive_id.to_url())
+    expected_exception = ArchiveConnectionError(
+        f"Failed to retrieve the expected HTML page at {expected_url}",
+        suggested_action=[
+            "Check your network connection.",
+            f"Make sure that you can access {expected_url} in your web browser.",
+        ],
+    )
+
+    with pytest.raises(ArchiveConnectionError) as e:
+        MetadataFactory(archive_id).fetch_versions()
+    assert e.type == ArchiveConnectionError
+    assert format(e.value) == format(expected_exception)
+
+
 @pytest.mark.parametrize(
     "version,extension,in_file,expect_out_file",
     [

`MetadataFactory` makes inappropriate assumptions about the HTML files it retrieves.
**Describe the bug**
`MetadataFactory` improperly assumes that HTML pages at download.qt.io will always contain a body that contains a table. Infrequently, the server will return something unexpected, and `aqt` should be able to provide a reasonable error message.

**To Reproduce**
Run `aqt list-qt linux desktop`, under the condition that the URL https://download.qt.io/online/qtsdkrepository/linux_x64/desktop/ returns a page without a table.


**Expected behavior**
The `aqt list-qt linux desktop` command returns a list of Qt versions.

**`aqt` output**

```
'NoneType' object has no attribute 'find_all'
Traceback (most recent call last):
File "/home/garald/.local/lib/python3.8/site-packages/aqt/installer.py", line 108, in run
args.func(args)
File "/home/garald/.local/lib/python3.8/site-packages/aqt/installer.py", line 524, in run_list_qt
show_list(meta)
File "/home/garald/.local/lib/python3.8/site-packages/aqt/metadata.py", line 775, in show_list
output = meta.getList()
File "/home/garald/.local/lib/python3.8/site-packages/aqt/metadata.py", line 435, in getList
return self._action()
File "/home/garald/.local/lib/python3.8/site-packages/aqt/metadata.py", line 473, in fetch_versions
versions = sorted(filter(None, map(get_version, filter(filter_by, versions_extensions))))
File "/home/garald/.local/lib/python3.8/site-packages/aqt/metadata.py", line 600, in iterate_folders
for row in soup.body.table.find_all("tr"):
AttributeError: 'NoneType' object has no attribute 'find_all'
aqtinstall(aqt) v2.1.0 on Python 3.8.10 [CPython GCC 9.4.0]
Working dir: /home/garald
Arguments: ['/home/garald/.local/bin/aqt', 'list-qt', 'linux', 'desktop'] Host: uname_result(system='Linux', node='garald-H310M-S2-2-0', release='5.4.0-109-generic', version='#123-Ubuntu SMP Fri Apr 8 09:10:54 UTC 2022', machine='x86_64', processor='x86_64')
===========================PLEASE FILE A BUG REPORT===========================
You have discovered a bug in aqt.
Please file a bug report at https://github.com/miurahr/aqtinstall/issues.
Please remember to include a copy of this program's output in your report.
```

**Desktop (please complete the following information):**
 - OS: Linux
 - aqtinstall(aqt) v2.1.0 on Python 3.8.10 [CPython GCC 9.4.0]

**Additional context**
This report comes from an off-topic comment posted in #496, but it is certainly a bug that needs to be addressed. I do not have all the context for this bug, but there's enough information in the program output to understand what happened.

tests/test_list.py::test_list_bad_html[<html><body>Login tests/test_list.py::test_list_bad_html[<html>malformed-html/]
tests/test_list.py::test_list_extension_for_arch[wasm_32-version0-wasm] tests/test_list.py::test_list_extension_for_arch[mingw-version1-] tests/test_list.py::test_list_extension_for_arch[android_fake-version2-] tests/test_list.py::test_list_extension_for_arch[android_x86-version3-] tests/test_list.py::test_list_extension_for_arch[android_x86-version4-x86] tests/test_list.py::test_list_extension_for_arch[android_x86-version5-x86] tests/test_list.py::test_list_possible_extension_for_arch[wasm_32-expect0] tests/test_list.py::test_list_possible_extension_for_arch[mingw-expect1] tests/test_list.py::test_list_possible_extension_for_arch[android_fake-expect2] tests/test_list.py::test_list_possible_extension_for_arch[android-expect3] tests/test_list.py::test_list_possible_extension_for_arch[android_x86-expect4] tests/test_list.py::test_versions[init_data0-[[Version('1.1.1'), tests/test_list.py::test_versions[init_data1-[]--expect_flat1-None-False] tests/test_list.py::test_versions[init_data2-[[Version('1.2.3')]]-1.2.3-expect_flat2-expect_last2-True] tests/test_list.py::test_list_versions_tools[windows-android-windows-android.html-windows-android-expect.json] tests/test_list.py::test_list_versions_tools[windows-desktop-windows-desktop.html-windows-desktop-expect.json] tests/test_list.py::test_list_versions_tools[windows-winrt-windows-winrt.html-windows-winrt-expect.json] tests/test_list.py::test_list_versions_tools[linux-android-linux-android.html-linux-android-expect.json] tests/test_list.py::test_list_versions_tools[linux-desktop-linux-desktop.html-linux-desktop-expect.json] tests/test_list.py::test_list_versions_tools[mac-android-mac-android.html-mac-android-expect.json] tests/test_list.py::test_list_versions_tools[mac-desktop-mac-desktop.html-mac-desktop-expect.json] tests/test_list.py::test_list_versions_tools[mac-ios-mac-ios.html-mac-ios-expect.json] tests/test_list.py::test_list_architectures_and_modules[5.14.0--windows-5140-update.xml-windows-5140-expect.json] tests/test_list.py::test_list_architectures_and_modules[5.15.0--windows-5150-update.xml-windows-5150-expect.json] tests/test_list.py::test_list_architectures_and_modules[5.15.2-src_doc_examples-windows-5152-src-doc-example-update.xml-windows-5152-src-doc-example-expect.json] tests/test_list.py::test_list_architectures_and_modules[6.2.0--windows-620-update.xml-windows-620-expect.json] tests/test_list.py::test_list_src_doc_examples_archives[src-windows-5.15.2-expected0] tests/test_list.py::test_list_src_doc_examples_archives[doc-windows-5.15.2-expected1] tests/test_list.py::test_list_src_doc_examples_archives[examples-windows-5.15.2-expected2] tests/test_list.py::test_list_src_doc_examples_modules[doc-windows-5.15.2-expected0] tests/test_list.py::test_list_src_doc_examples_modules[examples-windows-5.15.2-expected1] tests/test_list.py::test_list_src_doc_examples_cli[list-src tests/test_list.py::test_list_src_doc_examples_cli[list-doc tests/test_list.py::test_list_src_doc_examples_cli[list-example tests/test_list.py::test_list_archives[5.14.0-win32_mingw73-modules_to_query0-modules_failed_query0] tests/test_list.py::test_list_archives[5.14.0-win32_mingw73-modules_to_query1-modules_failed_query1] tests/test_list.py::test_list_archives[5.14.0-win32_mingw73-modules_to_query2-modules_failed_query2] tests/test_list.py::test_list_archives[5.14.0-win32_mingw73-modules_to_query3-modules_failed_query3] tests/test_list.py::test_list_archives[5.14.0-win64_msvc2017_64-modules_to_query4-modules_failed_query4] tests/test_list.py::test_list_archives[5.14.0-win64_msvc2017_64-modules_to_query5-modules_failed_query5] tests/test_list.py::test_list_archives_insufficient_args tests/test_list.py::test_list_archives_bad_xml tests/test_list.py::test_tool_modules[mac-desktop-tools_cmake] tests/test_list.py::test_tool_modules[mac-desktop-tools_ifw] tests/test_list.py::test_tool_modules[mac-desktop-tools_qtcreator] tests/test_list.py::test_list_qt_cli[--extensions tests/test_list.py::test_list_qt_cli[--spec tests/test_list.py::test_list_qt_cli[--modules tests/test_list.py::test_list_qt_cli[--extension tests/test_list.py::test_list_qt_cli[--arch tests/test_list.py::test_list_targets[list-qt-windows-expect0] tests/test_list.py::test_list_targets[list-qt-linux-expect1] tests/test_list.py::test_list_targets[list-qt-mac-expect2] tests/test_list.py::test_list_targets[list-tool-windows-expect3] tests/test_list.py::test_list_targets[list-tool-linux-expect4] tests/test_list.py::test_list_targets[list-tool-mac-expect5] tests/test_list.py::test_list_wrong_target[list-qt-windows-ios] tests/test_list.py::test_list_wrong_target[list-qt-linux-ios] tests/test_list.py::test_list_wrong_target[list-qt-linux-winrt] tests/test_list.py::test_list_wrong_target[list-qt-mac-winrt] tests/test_list.py::test_list_wrong_target[list-tool-windows-ios] tests/test_list.py::test_list_wrong_target[list-tool-linux-ios] tests/test_list.py::test_list_wrong_target[list-tool-linux-winrt] tests/test_list.py::test_list_wrong_target[list-tool-mac-winrt] tests/test_list.py::test_invalid_spec[list-qt-not tests/test_list.py::test_invalid_spec[list-qt-1...3] tests/test_list.py::test_invalid_spec[list-qt-] tests/test_list.py::test_invalid_spec[list-qt->3 tests/test_list.py::test_list_choose_tool_by_version[simple_spec0-mytool.999] tests/test_list.py::test_list_choose_tool_by_version[simple_spec1-mytool.999] tests/test_list.py::test_list_choose_tool_by_version[simple_spec2-mytool.355] tests/test_list.py::test_list_choose_tool_by_version[simple_spec3-mytool.300] tests/test_list.py::test_list_choose_tool_by_version[simple_spec4-mytool.355] tests/test_list.py::test_list_choose_tool_by_version[simple_spec5-mytool.350] tests/test_list.py::test_list_choose_tool_by_version[simple_spec6-None] tests/test_list.py::test_list_invalid_extensions[android--6.2.0-Qt tests/test_list.py::test_list_invalid_extensions[android-arm64_v8a-5.13.0-The tests/test_list.py::test_list_invalid_extensions[desktop-arm64_v8a-5.13.0-The tests/test_list.py::test_list_invalid_extensions[desktop-arm64_v8a-6.2.0-The tests/test_list.py::test_list_invalid_extensions[desktop-wasm-5.12.11-The tests/test_list.py::test_list_invalid_extensions[desktop-wasm-6.1.9-The tests/test_list.py::test_list_invalid_extensions[android-wasm-5.12.11-The tests/test_list.py::test_list_invalid_extensions[android-wasm-5.14.0-The tests/test_list.py::test_list_invalid_extensions[android-wasm-6.1.9-Qt tests/test_list.py::test_suggested_follow_up[meta0-expected_message0] tests/test_list.py::test_suggested_follow_up[meta1-expected_message1] tests/test_list.py::test_suggested_follow_up[meta2-expected_message2] tests/test_list.py::test_suggested_follow_up[meta3-expected_message3] tests/test_list.py::test_suggested_follow_up[meta4-expected_message4] tests/test_list.py::test_suggested_follow_up[meta5-expected_message5] tests/test_list.py::test_suggested_follow_up[meta6-expected_message6] tests/test_list.py::test_suggested_follow_up[meta7-expected_message7] tests/test_list.py::test_suggested_follow_up[meta8-expected_message8] tests/test_list.py::test_suggested_follow_up[meta9-expected_message9] tests/test_list.py::test_suggested_follow_up[meta10-expected_message10] tests/test_list.py::test_suggested_follow_up[meta11-expected_message11] tests/test_list.py::test_suggested_follow_up[meta12-expected_message12] tests/test_list.py::test_suggested_follow_up[meta13-expected_message13] tests/test_list.py::test_format_suggested_follow_up tests/test_list.py::test_format_suggested_follow_up_empty tests/test_list.py::test_list_describe_filters[meta0-qt/mac/desktop tests/test_list.py::test_list_describe_filters[meta1-qt/mac/desktop/wasm tests/test_list.py::test_list_describe_filters[meta2-qt/mac/desktop] tests/test_list.py::test_list_describe_filters[meta3-qt/mac/desktop/wasm] tests/test_list.py::test_list_to_version[archive_id0-None-5.12.42-expect0] tests/test_list.py::test_list_to_version[archive_id1-None-not tests/test_list.py::test_list_to_version[archive_id2-spec2-latest-expect2] tests/test_list.py::test_list_to_version[archive_id3-spec3-latest-expect3] tests/test_list.py::test_list_fetch_tool_by_simple_spec tests/test_list.py::test_show_list_tools_long_ifw[120-Tool tests/test_list.py::test_show_list_tools_long_ifw[80-Tool tests/test_list.py::test_show_list_tools_long_ifw[0-Tool tests/test_list.py::test_show_list_versions tests/test_list.py::test_show_list_tools tests/test_list.py::test_show_list_empty tests/test_list.py::test_show_list_bad_connection tests/test_list.py::test_list_tool_cli[mac-desktop-tools_cmake] tests/test_list.py::test_fetch_http_ok tests/test_list.py::test_fetch_http_failover tests/test_list.py::test_fetch_http_download_error[ArchiveDownloadError] tests/test_list.py::test_fetch_http_download_error[ArchiveConnectionError]