diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 25013c5..ace46ff 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -13,11 +13,11 @@ repos:
     hooks:
       - id: flake8
   - repo: https://github.com/adrienverge/yamllint
-    rev: v1.34.0
+    rev: v1.35.1
     hooks:
       - id: yamllint
   - repo: https://github.com/awslabs/cfn-python-lint
-    rev: v0.85.1
+    rev: v0.85.2
     hooks:
       - id: cfn-python-lint
         args:
diff --git a/sceptre/stack.py b/sceptre/stack.py
index 8a63309..fa5639a 100644
--- a/sceptre/stack.py
+++ b/sceptre/stack.py
@@ -9,7 +9,7 @@ This module implements a Stack class, which stores a Stack's data.
 
 import logging
 
-from typing import List, Any, Optional
+from typing import List, Dict, Union, Any, Optional
 from deprecation import deprecated
 
 from sceptre import __version__
@@ -26,6 +26,7 @@ from sceptre.resolvers import (
     ResolvableValueProperty,
     RecursiveResolve,
     PlaceholderType,
+    Resolver,
 )
 from sceptre.template import Template
 
@@ -262,7 +263,7 @@ class Stack:
         )
 
         self.s3_details = s3_details
-        self.parameters = parameters or {}
+        self.parameters = self._ensure_parameters(parameters or {})
         self.sceptre_user_data = sceptre_user_data or {}
         self.notifications = notifications or []
 
@@ -275,6 +276,30 @@ class Stack:
             )
         return value
 
+    def _ensure_parameters(
+        self, parameters: Dict[str, Any]
+    ) -> Dict[str, Union[str, List[Union[str, Resolver]], Resolver]]:
+        """Ensure CloudFormation parameters are of valid types"""
+
+        def is_valid(value: Any) -> bool:
+            return (
+                isinstance(value, str)
+                or (
+                    isinstance(value, list)
+                    and all(
+                        isinstance(item, str) or isinstance(item, Resolver)
+                        for item in value
+                    )
+                )
+                or isinstance(value, Resolver)
+            )
+
+        if not all(is_valid(value) for value in parameters.values()):
+            raise InvalidConfigFileError(
+                f"{self.name}: Values for parameters must be strings, lists or resolvers, got {parameters}"
+            )
+        return parameters
+
     def __repr__(self):
         return (
             "sceptre.stack.Stack("

diff --git a/tests/test_stack.py b/tests/test_stack.py
index 7e843e4..6f67e08 100644
--- a/tests/test_stack.py
+++ b/tests/test_stack.py
@@ -40,6 +40,11 @@ def stack_factory(**kwargs):
     return Stack(**call_kwargs)
 
 
+class FakeResolver(Resolver):
+    def resolve(self):
+        return "Fake"
+
+
 class TestStack(object):
     def setup_method(self, test_method):
         self.stack = Stack(
@@ -183,6 +188,46 @@ class TestStack(object):
                 obsolete="true",
             )
 
+    @pytest.mark.parametrize(
+        "parameters",
+        [
+            {"someNum": 1},
+            {"someBool": True},
+            {"aBadList": [1, 2, 3]},
+            {"aDict": {"foo": "bar"}},
+        ],
+    )
+    def test_init__invalid_parameters_raise_invalid_config_file_error(self, parameters):
+        with pytest.raises(InvalidConfigFileError):
+            Stack(
+                name="stack_name",
+                project_code="project_code",
+                template_handler_config={"type": "file"},
+                region="region",
+                parameters=parameters,
+            )
+
+    @pytest.mark.parametrize(
+        "parameters",
+        [
+            {"someNum": "1"},
+            {"someBool": "true"},
+            {"aList": ["aString", FakeResolver()]},
+            {"aResolver": FakeResolver()},
+        ],
+    )
+    def test_init__valid_parameters_do_not_raise_invalid_config_file_error(
+        self, parameters
+    ):
+        stack = Stack(
+            name="stack_name",
+            project_code="project_code",
+            template_handler_config={"type": "file"},
+            region="region",
+            parameters=parameters,
+        )
+        assert isinstance(stack, Stack)
+
     def test_stack_repr(self):
         assert (
             self.stack.__repr__() == "sceptre.stack.Stack("
@@ -248,14 +293,10 @@ class TestStack(object):
     def test_configuration_manager__sceptre_role_returns_value__returns_connection_manager_with_that_role(
         self,
     ):
-        class FakeResolver(Resolver):
-            def resolve(self):
-                return "role"
-
         self.stack.sceptre_role = FakeResolver()
 
         connection_manager = self.stack.connection_manager
-        assert connection_manager.sceptre_role == "role"
+        assert connection_manager.sceptre_role == "Fake"
 
     @fail_if_not_removed
     def test_iam_role__is_removed_on_removal_version(self):

Input parameters should be validated
### Subject of the issue
For historical reasons, Sceptre has never validated input parameters that are passed in to CloudFormation stack parameters. Blocks that contain bools, ints etc give rise to confusing failures. For example:

```yaml
parameters:
  someBool: true
```

Would lead to an error appearing like:
```
"Parameter validation failed:\nInvalid type for parameter Parameters[0].ParameterValue, value: 1, type: <class 'bool'>, valid types: <class 'str'>"  
```

In more complicated examples it is often quite unclear what `Parameter[0]` means.

A feature requested here to add a layer of input data validation at the time of Stack instantiation after discussion with @jfalkenstein  in Slack.

### Your environment
* version of sceptre (sceptre --version) latest
* version of python (python --version) 3.10
* which OS/distro

tests/test_stack.py::TestStack::test_init__invalid_parameters_raise_invalid_config_file_error[parameters0] tests/test_stack.py::TestStack::test_init__invalid_parameters_raise_invalid_config_file_error[parameters1] tests/test_stack.py::TestStack::test_init__invalid_parameters_raise_invalid_config_file_error[parameters2] tests/test_stack.py::TestStack::test_init__invalid_parameters_raise_invalid_config_file_error[parameters3]
tests/test_stack.py::TestStack::test_initialize_stack_with_template_path tests/test_stack.py::TestStack::test_initialize_stack_with_template_handler tests/test_stack.py::TestStack::test_raises_exception_if_path_and_handler_configured tests/test_stack.py::TestStack::test_init__non_boolean_ignore_value__raises_invalid_config_file_error tests/test_stack.py::TestStack::test_init__non_boolean_obsolete_value__raises_invalid_config_file_error tests/test_stack.py::TestStack::test_init__valid_parameters_do_not_raise_invalid_config_file_error[parameters0] tests/test_stack.py::TestStack::test_init__valid_parameters_do_not_raise_invalid_config_file_error[parameters1] tests/test_stack.py::TestStack::test_init__valid_parameters_do_not_raise_invalid_config_file_error[parameters2] tests/test_stack.py::TestStack::test_init__valid_parameters_do_not_raise_invalid_config_file_error[parameters3] tests/test_stack.py::TestStack::test_stack_repr tests/test_stack.py::TestStack::test_configuration_manager__sceptre_role_raises_recursive_resolve__returns_connection_manager_with_no_role tests/test_stack.py::TestStack::test_configuration_manager__sceptre_role_returns_value_second_access__returns_value_on_second_access tests/test_stack.py::TestStack::test_configuration_manager__sceptre_role_returns_value__returns_connection_manager_with_that_role tests/test_stack.py::TestStack::test_iam_role__is_removed_on_removal_version tests/test_stack.py::TestStack::test_role_arn__is_removed_on_removal_version tests/test_stack.py::TestStack::test_iam_role_session_duration__is_removed_on_removal_version tests/test_stack.py::TestStack::test_init__iam_role_set_resolves_to_sceptre_role tests/test_stack.py::TestStack::test_init__role_arn_set_resolves_to_cloudformation_service_role tests/test_stack.py::TestStack::test_init__iam_role_session_duration_set_resolves_to_sceptre_role_session_duration tests/test_stack.py::TestStackSceptreUserData::test_user_data_is_accessible tests/test_stack.py::TestStackSceptreUserData::test_user_data_gets_resolved tests/test_stack.py::TestStackSceptreUserData::test_recursive_user_data_gets_resolved