diff --git a/reframe/frontend/cli.py b/reframe/frontend/cli.py
index 9a465ea2..54436755 100644
--- a/reframe/frontend/cli.py
+++ b/reframe/frontend/cli.py
@@ -737,16 +737,22 @@ def main():
 
         # Update options from the selected execution mode
         if options.mode:
-            mode_args = site_config.get(f'modes/@{options.mode}/options')
-
-            # We lexically split the mode options, because otherwise spaces
-            # will be treated as part of the option argument; see GH bug #1554
-            mode_args = list(itertools.chain.from_iterable(shlex.split(m)
-                                                           for m in mode_args))
-            # Parse the mode's options and reparse the command-line
-            options = argparser.parse_args(mode_args)
-            options = argparser.parse_args(namespace=options.cmd_options)
-            options.update_config(site_config)
+            mode = site_config.get(f'modes/@{options.mode}')
+            if mode is None:
+                printer.warning(f'invalid mode: {options.mode!r}; ignoring...')
+            else:
+                mode_args = site_config.get(f'modes/@{options.mode}/options')
+
+                # We lexically split the mode options, because otherwise spaces
+                # will be treated as part of the option argument;
+                # see GH bug #1554
+                mode_args = list(
+                    itertools.chain.from_iterable(shlex.split(m)
+                                                  for m in mode_args))
+                # Parse the mode's options and reparse the command-line
+                options = argparser.parse_args(mode_args)
+                options = argparser.parse_args(namespace=options.cmd_options)
+                options.update_config(site_config)
 
         logging.configure_logging(site_config)
     except (OSError, errors.ConfigError) as e:

diff --git a/unittests/test_cli.py b/unittests/test_cli.py
index bfdb59f3..adfe5d0f 100644
--- a/unittests/test_cli.py
+++ b/unittests/test_cli.py
@@ -478,6 +478,20 @@ def test_execution_modes(run_reframe):
     assert 'Ran 2/2 test case' in stdout
 
 
+def test_invalid_mode_warning(run_reframe):
+    mode = 'invalid'
+    returncode, stdout, stderr = run_reframe(
+        action='list',
+        checkpath=[],
+        environs=[],
+        local=False,
+        mode=mode
+    )
+    assert 'Traceback' not in stdout
+    assert 'Traceback' not in stderr
+    assert f'invalid mode: {mode!r}; ignoring' in stdout
+
+
 def test_timestamp_option(run_reframe):
     timefmt = time.strftime('xxx_%F')
     returncode, stdout, _ = run_reframe(

Issue a warning if an execution mode requested with `--mode` is not found
Currently no warning is issued: `reframe --mode=foo -l`.
unittests/test_cli.py::test_invalid_mode_warning
unittests/test_cli.py::test_check_success unittests/test_cli.py::test_check_restore_session_failed unittests/test_cli.py::test_check_restore_session_succeeded_test unittests/test_cli.py::test_check_restore_session_check_search_path unittests/test_cli.py::test_check_success_force_local unittests/test_cli.py::test_report_file_with_sessionid unittests/test_cli.py::test_report_ends_with_newline unittests/test_cli.py::test_check_failure unittests/test_cli.py::test_check_setup_failure unittests/test_cli.py::test_check_kbd_interrupt unittests/test_cli.py::test_check_sanity_failure unittests/test_cli.py::test_dont_restage unittests/test_cli.py::test_checkpath_symlink unittests/test_cli.py::test_performance_check_failure unittests/test_cli.py::test_perflogdir_from_env unittests/test_cli.py::test_performance_report unittests/test_cli.py::test_skip_system_check_option unittests/test_cli.py::test_skip_prgenv_check_option unittests/test_cli.py::test_sanity_of_checks unittests/test_cli.py::test_unknown_system unittests/test_cli.py::test_sanity_of_optconfig unittests/test_cli.py::test_checkpath_recursion unittests/test_cli.py::test_same_output_stage_dir unittests/test_cli.py::test_execution_modes unittests/test_cli.py::test_timestamp_option unittests/test_cli.py::test_timestamp_option_default unittests/test_cli.py::test_list_empty_prgenvs_check_and_options unittests/test_cli.py::test_list_check_with_empty_prgenvs unittests/test_cli.py::test_list_empty_prgenvs_in_check_and_options unittests/test_cli.py::test_list_with_details unittests/test_cli.py::test_list_concretized unittests/test_cli.py::test_list_tags unittests/test_cli.py::test_filtering_multiple_criteria_name unittests/test_cli.py::test_filtering_multiple_criteria_hash unittests/test_cli.py::test_filtering_exclude_hash unittests/test_cli.py::test_show_config_all unittests/test_cli.py::test_show_config_param unittests/test_cli.py::test_show_config_unknown_param unittests/test_cli.py::test_show_config_null_param unittests/test_cli.py::test_verbosity unittests/test_cli.py::test_verbosity_with_check unittests/test_cli.py::test_quiesce_with_check unittests/test_cli.py::test_failure_stats unittests/test_cli.py::test_maxfail_option unittests/test_cli.py::test_maxfail_invalid_option unittests/test_cli.py::test_maxfail_negative unittests/test_cli.py::test_repeat_option unittests/test_cli.py::test_repeat_invalid_option unittests/test_cli.py::test_repeat_negative unittests/test_cli.py::test_exec_order[name] unittests/test_cli.py::test_exec_order[rname] unittests/test_cli.py::test_exec_order[uid] unittests/test_cli.py::test_exec_order[ruid] unittests/test_cli.py::test_exec_order[random] unittests/test_cli.py::test_detect_host_topology unittests/test_cli.py::test_detect_host_topology_file unittests/test_cli.py::test_external_vars unittests/test_cli.py::test_external_vars_invalid_expr unittests/test_cli.py::test_fixture_registry_env_sys unittests/test_cli.py::test_fixture_resolution unittests/test_cli.py::test_dynamic_tests unittests/test_cli.py::test_dynamic_tests_filtering unittests/test_cli.py::test_testlib_inherit_fixture_in_different_files