diff --git a/force_bdss/core/tests/test_verifier.py b/force_bdss/core/tests/test_verifier.py
new file mode 100644
index 0000000000000000000000000000000000000000..6c5ea3569d928820a4469f4f2154a18040aa92b2
--- /dev/null
+++ b/force_bdss/core/tests/test_verifier.py
@@ -0,0 +1,92 @@
+import unittest
+
+from force_bdss.core.execution_layer import ExecutionLayer
+from force_bdss.core.input_slot_info import InputSlotInfo
+from force_bdss.core.output_slot_info import OutputSlotInfo
+from force_bdss.core.verifier import verify_workflow
+from force_bdss.core.workflow import Workflow
+from force_bdss.tests.dummy_classes.extension_plugin import \
+    DummyExtensionPlugin
+
+
+class TestVerifier(unittest.TestCase):
+    def setUp(self):
+        self.plugin = DummyExtensionPlugin()
+        self.workflow = Workflow()
+
+    def test_empty_workflow(self):
+        wf = self.workflow
+        errors = verify_workflow(wf)
+        self.assertEqual(len(errors), 2)
+        self.assertEqual(errors[0].subject, wf)
+        self.assertIn("no MCO", errors[0].error)
+
+        self.assertEqual(errors[1].subject, wf)
+        self.assertIn("no execution layers", errors[1].error)
+
+    def test_no_mco_parameters(self):
+        wf = self.workflow
+        wf.mco = self.plugin.mco_factories[0].create_model()
+
+        errors = verify_workflow(wf)
+        self.assertEqual(len(errors), 2)
+        self.assertEqual(errors[0].subject, wf.mco)
+        self.assertIn("no defined parameters", errors[0].error)
+
+    def test_parameters_empty_names(self):
+        wf = self.workflow
+        mco_factory = self.plugin.mco_factories[0]
+        wf.mco = mco_factory.create_model()
+        parameter_factory = mco_factory.parameter_factories()[0]
+        wf.mco.parameters.append(parameter_factory.create_model())
+
+        errors = verify_workflow(wf)
+        self.assertEqual(len(errors), 3)
+        self.assertEqual(errors[0].subject, wf.mco.parameters[0])
+        self.assertIn("empty name", errors[0].error)
+        self.assertEqual(errors[1].subject, wf.mco.parameters[0])
+        self.assertIn("empty type", errors[1].error)
+
+    def test_data_sources(self):
+        wf = self.workflow
+        mco_factory = self.plugin.mco_factories[0]
+        wf.mco = mco_factory.create_model()
+        parameter_factory = mco_factory.parameter_factories()[0]
+        wf.mco.parameters.append(parameter_factory.create_model())
+        wf.mco.parameters[0].name = "name"
+        wf.mco.parameters[0].type = "type"
+
+        layer = ExecutionLayer()
+        wf.execution_layers.append(layer)
+        ds_factory = self.plugin.data_source_factories[0]
+        ds_model = ds_factory.create_model()
+        layer.data_sources.append(ds_model)
+
+        errors = verify_workflow(wf)
+        self.assertEqual(errors[0].subject, ds_model)
+        self.assertIn("Missing input slot name assignment", errors[0].error)
+
+        ds_model.input_slot_info.append(
+            InputSlotInfo(name="name")
+        )
+
+        errors = verify_workflow(wf)
+        self.assertEqual(errors[0].subject, ds_model)
+        self.assertIn("Missing output slot name assignment", errors[0].error)
+
+        ds_model.output_slot_info.append(
+            OutputSlotInfo(name="name")
+        )
+
+        errors = verify_workflow(wf)
+        self.assertEqual(len(errors), 0)
+
+        ds_model.input_slot_info[0].name = ''
+        errors = verify_workflow(wf)
+        self.assertEqual(len(errors), 1)
+        self.assertIn("Undefined name for input parameter", errors[0].error)
+
+        ds_model.output_slot_info[0].name = ''
+        errors = verify_workflow(wf)
+        self.assertEqual(len(errors), 2)
+        self.assertIn("Undefined name for output parameter", errors[1].error)
diff --git a/force_bdss/core/verifier.py b/force_bdss/core/verifier.py
new file mode 100644
index 0000000000000000000000000000000000000000..3361f35fc143a2b0b9bac09e1ca594cc548e57e3
--- /dev/null
+++ b/force_bdss/core/verifier.py
@@ -0,0 +1,122 @@
+import logging
+from traits.api import HasStrictTraits, Str, Any
+
+logger = logging.getLogger(__name__)
+
+
+class VerifierError(HasStrictTraits):
+    subject = Any()
+    error = Str()
+
+
+def verify_workflow(workflow):
+    """Verifies if the workflow can be executed, and specifies where the
+    error occurs and why.
+
+    """
+    result = []
+
+    result.extend(_check_mco(workflow))
+    result.extend(_check_execution_layers(workflow))
+
+    return result
+
+
+def _check_mco(workflow):
+    errors = []
+    if workflow.mco is None:
+        errors.append(
+            VerifierError(
+                subject=workflow,
+                error="Workflow has no MCO"
+            )
+        )
+        return errors
+
+    mco = workflow.mco
+    if len(mco.parameters) == 0:
+        errors.append(VerifierError(subject=mco,
+                                    error="MCO has no defined parameters"))
+
+    for param in mco.parameters:
+        if len(param.name.strip()) == 0:
+            errors.append(VerifierError(subject=param,
+                                        error="Parameter has empty name"))
+        if len(param.type.strip()) == 0:
+            errors.append(VerifierError(subject=param,
+                                        error="Parameter has empty type"))
+    return errors
+
+
+def _check_execution_layers(workflow):
+    errors = []
+
+    layers = workflow.execution_layers
+    if len(layers) == 0:
+        errors.append(
+            VerifierError(
+                subject=workflow,
+                error="Workflow has no execution layers"
+            )
+        )
+
+        return errors
+
+    for layer in layers:
+        if len(layer.data_sources) == 0:
+            errors.append(VerifierError(subject=layer,
+                                        error="Layer has no data sources"))
+
+        for ds in layer.data_sources:
+            errors.extend(_check_data_source(ds))
+
+    return errors
+
+
+def _check_data_source(data_source_model):
+    errors = []
+
+    factory = data_source_model.factory
+    try:
+        data_source = factory.create_data_source()
+    except Exception:
+        logger.exception("Unable to create data source from factory"
+                         " '{}', plugin '{}'. This might indicate a "
+                         "programming error".format(factory.id,
+                                                    factory.plugin.id))
+        raise
+
+    try:
+        input_slots, output_slots = data_source.slots(data_source_model)
+    except Exception:
+        logger.exception(
+            "Unable to retrieve slot information from data source"
+            " created by factory '{}', plugin '{}'. This might "
+            "indicate a programming error.".format(
+                data_source.factory.id,
+                data_source.factory.plugin.id))
+        raise
+
+    if len(input_slots) != len(data_source_model.input_slot_info):
+        errors.append(VerifierError(
+            subject=data_source_model,
+            error="Missing input slot name assignment"))
+
+    for idx, info in enumerate(data_source_model.input_slot_info):
+        if len(info.name.strip()) == 0:
+            errors.append(VerifierError(
+                subject=data_source_model,
+                error="Undefined name for input parameter {}".format(idx)))
+
+    if len(output_slots) != len(data_source_model.output_slot_info):
+        errors.append(VerifierError(
+            subject=data_source_model,
+            error="Missing output slot name assignment"))
+
+    for idx, info in enumerate(data_source_model.output_slot_info):
+        if len(info.name.strip()) == 0:
+            errors.append(VerifierError(
+                subject=data_source_model,
+                error="Undefined name for output parameter {}".format(idx)))
+
+    return errors
diff --git a/force_bdss/tests/dummy_classes/data_source.py b/force_bdss/tests/dummy_classes/data_source.py
index b53cb5cbcc6aff2689ffe790f2d84f2a1d372fc7..c4547881d5edae073c31044feeaf7b2c4b852406 100644
--- a/force_bdss/tests/dummy_classes/data_source.py
+++ b/force_bdss/tests/dummy_classes/data_source.py
@@ -1,3 +1,4 @@
+from force_bdss.core.slot import Slot
 from force_bdss.data_sources.base_data_source import BaseDataSource
 from force_bdss.data_sources.base_data_source_factory import \
     BaseDataSourceFactory
@@ -9,7 +10,11 @@ class DummyDataSource(BaseDataSource):
         pass
 
     def slots(self, model):
-        return (), ()
+        return (
+            Slot(type="TYPE1"),
+               ), (
+            Slot(type="TYPE2"),
+        )
 
 
 class DummyDataSourceModel(BaseDataSourceModel):