diff --git a/src/language/ASTNodeDataType.cpp b/src/language/ASTNodeDataType.cpp
index 942336835c22e5934565d327af0481bad8df10ec..0c5bdb27aa3c603c31e3d9be2e4930f42f9ecf03 100644
--- a/src/language/ASTNodeDataType.cpp
+++ b/src/language/ASTNodeDataType.cpp
@@ -2,6 +2,7 @@
 
 #include <language/ASTNode.hpp>
 #include <language/PEGGrammar.hpp>
+#include <utils/PugsAssert.hpp>
 
 ASTNodeDataType
 getVectorDataType(const ASTNode& type_node)
@@ -90,11 +91,14 @@ dataTypePromotion(const ASTNodeDataType& data_type_1, const ASTNodeDataType& dat
 bool
 isNaturalConversion(const ASTNodeDataType& data_type, const ASTNodeDataType& target_data_type)
 {
+  Assert((data_type != ASTNodeDataType::undefined_t) and (target_data_type != ASTNodeDataType::undefined_t));
   if (target_data_type == data_type) {
-    if (data_type != ASTNodeDataType::type_id_t) {
-      return true;
-    } else {
+    if (data_type == ASTNodeDataType::type_id_t) {
       return (data_type.typeName() == target_data_type.typeName());
+    } else if (data_type == ASTNodeDataType::vector_t) {
+      return (data_type.dimension() == target_data_type.dimension());
+    } else {
+      return true;
     }
   } else if (target_data_type == ASTNodeDataType::bool_t) {
     return false;
diff --git a/src/language/ASTNodeDataTypeBuilder.cpp b/src/language/ASTNodeDataTypeBuilder.cpp
index a03abf3a9b8318813bb7e4241f33ec9e214c189d..7ae2758fd2472cad4a63523734a59d6a40814fc8 100644
--- a/src/language/ASTNodeDataTypeBuilder.cpp
+++ b/src/language/ASTNodeDataTypeBuilder.cpp
@@ -207,6 +207,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
           for (size_t i = 0; i < nb_parameter_domains; ++i) {
             simple_type_allocator(*parameters_domain_node.children[i], *parameters_name_node.children[i]);
           }
+          parameters_name_node.m_data_type = ASTNodeDataType::list_t;
         }
 
         // build types for compound types
@@ -283,6 +284,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
         }
 
         n.m_data_type = ASTNodeDataType::void_t;
+        return;
       } else if (n.is_type<language::name>()) {
         std::shared_ptr<SymbolTable>& symbol_table = n.m_symbol_table;
 
@@ -442,9 +444,7 @@ ASTNodeDataTypeBuilder::_buildNodeDataTypes(ASTNode& n) const
                n.is_type<language::vector_type>() or n.is_type<language::type_name_id>()) {
       n.m_data_type = ASTNodeDataType::typename_t;
     } else if (n.is_type<language::name_list>() or n.is_type<language::lvalue_list>() or
-               n.is_type<language::function_argument_list>()) {
-      n.m_data_type = ASTNodeDataType::void_t;
-    } else if (n.is_type<language::expression_list>()) {
+               n.is_type<language::function_argument_list>() or n.is_type<language::expression_list>()) {
       n.m_data_type = ASTNodeDataType::list_t;
     }
   }
diff --git a/src/language/ASTNodeNaturalConversionChecker.cpp b/src/language/ASTNodeNaturalConversionChecker.cpp
index d7027ce1a1650d02c92e06191fadaf371dcb50ca..e80cd262302a379e516da18955c6cd9bb954783d 100644
--- a/src/language/ASTNodeNaturalConversionChecker.cpp
+++ b/src/language/ASTNodeNaturalConversionChecker.cpp
@@ -1,6 +1,7 @@
 #include <language/ASTNodeNaturalConversionChecker.hpp>
 
 #include <language/PEGGrammar.hpp>
+#include <utils/Exceptions.hpp>
 
 void
 ASTNodeNaturalConversionChecker::_checkIsNaturalTypeConversion(const ASTNode& node,
@@ -12,7 +13,12 @@ ASTNodeNaturalConversionChecker::_checkIsNaturalTypeConversion(const ASTNode& no
     error_message << "invalid implicit conversion: ";
     error_message << rang::fgB::red << dataTypeName(data_type) << " -> " << dataTypeName(target_data_type)
                   << rang::fg::reset;
-    throw parse_error(error_message.str(), node.begin());
+
+    if ((data_type == ASTNodeDataType::undefined_t) or (target_data_type == ASTNodeDataType::undefined_t)) {
+      throw UnexpectedError(error_message.str());
+    } else {
+      throw parse_error(error_message.str(), node.begin());
+    }
   }
 }
 
diff --git a/src/language/ASTSymbolTableBuilder.cpp b/src/language/ASTSymbolTableBuilder.cpp
index f0ed7ece39d53efb1810aeff55869d0119017040..07dc16e33bed3376b88fe65e1f733b4c22eb2225 100644
--- a/src/language/ASTSymbolTableBuilder.cpp
+++ b/src/language/ASTSymbolTableBuilder.cpp
@@ -33,7 +33,7 @@ ASTSymbolTableBuilder::buildSymbolTable(ASTNode& n, std::shared_ptr<SymbolTable>
     }
 
     size_t function_id =
-      symbol_table->functionTable().add(FunctionDescriptor{std::move(n.children[1]), std::move(n.children[2])});
+      symbol_table->functionTable().add(FunctionDescriptor{symbol, std::move(n.children[1]), std::move(n.children[2])});
     i_symbol->attributes().value() = function_id;
     n.children.resize(1);
   } else {
diff --git a/src/language/BuiltinFunctionEmbedder.hpp b/src/language/BuiltinFunctionEmbedder.hpp
index 79eb78e4c277d1ef54c70c6ef123143c1b2fc0a6..169a1f19605ffb4c9656c99330a82bb79afb3a16 100644
--- a/src/language/BuiltinFunctionEmbedder.hpp
+++ b/src/language/BuiltinFunctionEmbedder.hpp
@@ -5,6 +5,7 @@
 #include <language/DataHandler.hpp>
 #include <language/DataVariant.hpp>
 #include <language/FunctionTable.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
 #include <utils/Demangle.hpp>
 #include <utils/Exceptions.hpp>
 #include <utils/PugsTraits.hpp>
@@ -13,22 +14,6 @@
 #include <memory>
 #include <vector>
 
-template <typename T>
-inline ASTNodeDataType ast_node_data_type_from = ASTNodeDataType::undefined_t;
-
-template <>
-inline ASTNodeDataType ast_node_data_type_from<void> = ASTNodeDataType::void_t;
-template <>
-inline ASTNodeDataType ast_node_data_type_from<bool> = ASTNodeDataType::bool_t;
-template <>
-inline ASTNodeDataType ast_node_data_type_from<int64_t> = ASTNodeDataType::int_t;
-template <>
-inline ASTNodeDataType ast_node_data_type_from<uint64_t> = ASTNodeDataType::unsigned_int_t;
-template <>
-inline ASTNodeDataType ast_node_data_type_from<double> = ASTNodeDataType::double_t;
-template <>
-inline ASTNodeDataType ast_node_data_type_from<std::string> = ASTNodeDataType::string_t;
-
 class IBuiltinFunctionEmbedder
 {
  public:
diff --git a/src/language/FunctionTable.hpp b/src/language/FunctionTable.hpp
index a2b7b95af19f2f7317285fda0612fccdfaaad95d..af262d1962209aa9f10476448ebee78f5cba3fa3 100644
--- a/src/language/FunctionTable.hpp
+++ b/src/language/FunctionTable.hpp
@@ -10,10 +10,18 @@
 
 class FunctionDescriptor
 {
+  std::string m_name;
+
   std::unique_ptr<ASTNode> m_domain_mapping_node;
   std::unique_ptr<ASTNode> m_definition_node;
 
  public:
+  const std::string&
+  name() const
+  {
+    return m_name;
+  }
+
   auto&
   domainMappingNode() const
   {
@@ -30,8 +38,10 @@ class FunctionDescriptor
 
   FunctionDescriptor& operator=(FunctionDescriptor&&) = default;
 
-  FunctionDescriptor(std::unique_ptr<ASTNode>&& domain_mapping_node, std::unique_ptr<ASTNode>&& definition_node)
-    : m_domain_mapping_node(std::move(domain_mapping_node)), m_definition_node(std::move(definition_node))
+  FunctionDescriptor(const std::string& name,
+                     std::unique_ptr<ASTNode>&& domain_mapping_node,
+                     std::unique_ptr<ASTNode>&& definition_node)
+    : m_name{name}, m_domain_mapping_node(std::move(domain_mapping_node)), m_definition_node(std::move(definition_node))
   {}
 
   FunctionDescriptor(FunctionDescriptor&&) = default;
diff --git a/src/language/MeshModule.cpp b/src/language/MeshModule.cpp
index cd987e244f3ce1204c998a687562f077db5aea5b..b8e64da519aa99b49d6a8858d0f8b6bf01aa978b 100644
--- a/src/language/MeshModule.cpp
+++ b/src/language/MeshModule.cpp
@@ -12,14 +12,13 @@
 #include <utils/Exceptions.hpp>
 
 #include <Kokkos_Core.hpp>
+
+#include <array>
 #include <cstdio>
 
 template <>
 inline ASTNodeDataType ast_node_data_type_from<std::shared_ptr<IMesh>> = {ASTNodeDataType::type_id_t, "mesh"};
 
-template <>
-inline ASTNodeDataType ast_node_data_type_from<FunctionSymbolId> = {ASTNodeDataType::function_t};
-
 template <typename T>
 class MeshTransformation;
 template <typename OutputType, typename... InputType>
@@ -30,13 +29,16 @@ class MeshTransformation<OutputType(InputType...)> : public PugsFunctionAdapter<
 
  public:
   static inline std::shared_ptr<Mesh<Connectivity<Dimension>>>
-  transform(FunctionSymbolId function_symbol_id, std::shared_ptr<const IMesh> p_mesh)
+  transform(const FunctionSymbolId& function_symbol_id, std::shared_ptr<const IMesh> p_mesh)
   {
     using MeshType             = Mesh<Connectivity<Dimension>>;
     const MeshType& given_mesh = dynamic_cast<const MeshType&>(*p_mesh);
 
-    auto& expression                    = Adapter::getFunctionExpression(function_symbol_id);
-    auto convert_result                 = Adapter::getResultConverter(expression.m_data_type);
+    const auto flatten_args = Adapter::getFlattenArgs(function_symbol_id);
+
+    auto& expression    = Adapter::getFunctionExpression(function_symbol_id);
+    auto convert_result = Adapter::getResultConverter(expression.m_data_type);
+
     Array<ExecutionPolicy> context_list = Adapter::getContextList(expression);
 
     NodeValue<const OutputType> given_xr = given_mesh.xr();
@@ -45,13 +47,14 @@ class MeshTransformation<OutputType(InputType...)> : public PugsFunctionAdapter<
     using execution_space = typename Kokkos::DefaultExecutionSpace::execution_space;
     Kokkos::Experimental::UniqueToken<execution_space, Kokkos::Experimental::UniqueTokenScope::Global> tokens;
 
-    parallel_for(given_mesh.numberOfNodes(), [=, &expression, &tokens](NodeId r) {
+    parallel_for(given_mesh.numberOfNodes(), [=, &expression, &flatten_args, &tokens](NodeId r) {
       const int32_t t = tokens.acquire();
 
       auto& execution_policy = context_list[t];
 
-      Adapter::convertArgs(execution_policy.currentContext(), given_xr[r]);
-      xr[r] = convert_result(expression.execute(execution_policy));
+      Adapter::convertArgs(execution_policy.currentContext(), flatten_args, given_xr[r]);
+      auto result = expression.execute(execution_policy);
+      xr[r]       = convert_result(std::move(result));
 
       tokens.release(t);
     });
@@ -80,7 +83,7 @@ MeshModule::MeshModule()
                                                                      FunctionSymbolId>>(
                               std::function<std::shared_ptr<IMesh>(std::shared_ptr<IMesh>, FunctionSymbolId)>{
                                 [](std::shared_ptr<IMesh> p_mesh,
-                                   FunctionSymbolId function_id) -> std::shared_ptr<IMesh> {
+                                   const FunctionSymbolId& function_id) -> std::shared_ptr<IMesh> {
                                   switch (p_mesh->dimension()) {
                                   case 1: {
                                     using TransformT = TinyVector<1>(TinyVector<1>);
@@ -95,7 +98,7 @@ MeshModule::MeshModule()
                                     return MeshTransformation<TransformT>::transform(function_id, p_mesh);
                                   }
                                   default: {
-                                    throw NormalError("invalid mesh dimension");
+                                    throw UnexpectedError("invalid mesh dimension");
                                   }
                                   }
                                 }}
diff --git a/src/language/PugsFunctionAdapter.hpp b/src/language/PugsFunctionAdapter.hpp
index 262299728209cdfc7310c690c09ce74c0f22d494..fc2b752cbadeaa8ebf0aad1bd90c6c5bdd65d1f8 100644
--- a/src/language/PugsFunctionAdapter.hpp
+++ b/src/language/PugsFunctionAdapter.hpp
@@ -2,38 +2,177 @@
 #define PUGS_FUNCTION_ADAPTER_HPP
 
 #include <language/ASTNode.hpp>
+#include <language/ASTNodeDataType.hpp>
 #include <language/SymbolTable.hpp>
 #include <language/node_processor/ExecutionPolicy.hpp>
+#include <language/utils/ASTNodeDataTypeTraits.hpp>
+#include <language/utils/RuntimeError.hpp>
 #include <utils/Array.hpp>
 #include <utils/Exceptions.hpp>
 #include <utils/PugsMacros.hpp>
 
 #include <Kokkos_Core.hpp>
 
+#include <array>
+
 template <typename T>
 class PugsFunctionAdapter;
 template <typename OutputType, typename... InputType>
 class PugsFunctionAdapter<OutputType(InputType...)>
 {
+ protected:
+  using FlattenList = std::array<int32_t, sizeof...(InputType)>;
+
  private:
+  template <typename T>
+  PUGS_INLINE static void
+  _flattenArgT(const T&, ExecutionPolicy::Context&, size_t&)
+  {
+    throw UnexpectedError("cannot flatten type " + demangle<T>());
+  }
+
+  template <size_t N>
+  PUGS_INLINE static void
+  _flattenArgT(const TinyVector<N>& t, ExecutionPolicy::Context& context, size_t& i_context)
+  {
+    for (size_t i = 0; i < N; ++i) {
+      context[i_context + i] = t[i];
+    }
+  }
+
   template <typename T, typename... Args>
   PUGS_INLINE static void
-  _convertArgs(const Args&&... args, const T& t, ExecutionPolicy::Context& context)
+  _convertArgs(const T& t,
+               const Args&&... args,
+               ExecutionPolicy::Context& context,
+               const FlattenList& flatten,
+               size_t i_context)
   {
-    context[sizeof...(args)] = t;
+    if (flatten[sizeof...(args)]) {
+      _flattenArgT(t, context, i_context);
+    } else {
+      context[i_context++] = t;
+    }
     if constexpr (sizeof...(args) > 0) {
-      _convertArgs(std::forward<Args>(args)..., context);
+      _convertArgs(std::forward<Args>(args)..., context, flatten, i_context);
     }
   }
 
+  template <typename Arg, typename... RemainingArgs>
+  [[nodiscard]] PUGS_INLINE static bool
+  _checkValidArgumentDataType(const ASTNode& input_expression, FlattenList& flatten_list) noexcept
+  {
+    constexpr const ASTNodeDataType& expected_input_data_type = ast_node_data_type_from<Arg>;
+    const ASTNodeDataType& input_data_type                    = input_expression.m_data_type;
+
+    constexpr size_t i_argument = sizeof...(InputType) - 1 - sizeof...(RemainingArgs);
+    flatten_list[i_argument]    = false;
+
+    if (not isNaturalConversion(expected_input_data_type, input_data_type)) {
+      if ((expected_input_data_type == ASTNodeDataType::vector_t) and (input_data_type == ASTNodeDataType::list_t)) {
+        flatten_list[i_argument] = true;
+        if (expected_input_data_type.dimension() != input_expression.children.size()) {
+          return false;
+        } else {
+          for (const auto& child : input_expression.children) {
+            const ASTNodeDataType& data_type = child->m_data_type;
+            if (not isNaturalConversion(ast_node_data_type_from<double>, data_type)) {
+              return false;
+            }
+          }
+        }
+      } else {
+        return false;
+      }
+    }
+    if constexpr (sizeof...(RemainingArgs) == 0) {
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  [[nodiscard]] PUGS_INLINE static bool
+  _checkValidInputDataType(const ASTNode& input_expression, FlattenList& flatten_list) noexcept
+  {
+    return _checkValidArgumentDataType<InputType...>(input_expression, flatten_list);
+  }
+
+  [[nodiscard]] PUGS_INLINE static bool
+  _checkValidOutputDataType(const ASTNode& return_expression) noexcept
+  {
+    constexpr const ASTNodeDataType& expected_return_data_type = ast_node_data_type_from<OutputType>;
+    const ASTNodeDataType& return_data_type                    = return_expression.m_data_type;
+
+    if (not isNaturalConversion(return_data_type, expected_return_data_type)) {
+      if (expected_return_data_type == ASTNodeDataType::vector_t) {
+        if (return_data_type == ASTNodeDataType::list_t) {
+          if (expected_return_data_type.dimension() != return_expression.children.size()) {
+            return false;
+          } else {
+            for (const auto& child : return_expression.children) {
+              const ASTNodeDataType& data_type = child->m_data_type;
+              if (not isNaturalConversion(data_type, ast_node_data_type_from<double>)) {
+                return false;
+              }
+            }
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+  template <typename Arg, typename... RemainingArgs>
+  [[nodiscard]] PUGS_INLINE static std::string
+  _getCompoundTypeName()
+  {
+    if constexpr (sizeof...(RemainingArgs) > 0) {
+      return dataTypeName(ast_node_data_type_from<Arg>) + _getCompoundTypeName<RemainingArgs...>();
+    } else {
+      return dataTypeName(ast_node_data_type_from<Arg>);
+    }
+  }
+
+  [[nodiscard]] static std::string
+  _getInputDataTypeName()
+  {
+    return _getCompoundTypeName<InputType...>();
+  }
+
  protected:
-  PUGS_INLINE static auto&
-  getFunctionExpression(FunctionSymbolId function_symbol_id)
+  [[nodiscard]] PUGS_INLINE static FlattenList
+  getFlattenArgs(const FunctionSymbolId& function_symbol_id)
+  {
+    auto& function = function_symbol_id.symbolTable().functionTable()[function_symbol_id.id()];
+
+    FlattenList flatten_list;
+
+    bool has_valid_input  = _checkValidInputDataType(*function.definitionNode().children[0], flatten_list);
+    bool has_valid_output = _checkValidOutputDataType(*function.definitionNode().children[1]);
+
+    if (not(has_valid_input and has_valid_output)) {
+      std::ostringstream error_message;
+      error_message << "invalid function type" << rang::style::reset << "\nnote: expecting " << rang::fgB::yellow
+                    << _getInputDataTypeName() << " -> " << dataTypeName(ast_node_data_type_from<OutputType>)
+                    << rang::style::reset << '\n'
+                    << "note: provided function " << rang::fgB::magenta << function.name() << ": "
+                    << function.domainMappingNode().string() << rang::style::reset << std::ends;
+      throw RuntimeError(error_message.str());
+    }
+
+    return flatten_list;
+  }
+
+  [[nodiscard]] PUGS_INLINE static auto&
+  getFunctionExpression(const FunctionSymbolId& function_symbol_id)
   {
-    return *function_symbol_id.symbolTable().functionTable()[function_symbol_id.id()].definitionNode().children[1];
+    auto& function = function_symbol_id.symbolTable().functionTable()[function_symbol_id.id()];
+
+    return *function.definitionNode().children[1];
   }
 
-  PUGS_INLINE static auto
+  [[nodiscard]] PUGS_INLINE static auto
   getContextList(const ASTNode& expression)
   {
     Array<ExecutionPolicy> context_list(Kokkos::DefaultExecutionSpace::impl_thread_pool_size());
@@ -50,14 +189,14 @@ class PugsFunctionAdapter<OutputType(InputType...)>
 
   template <typename... Args>
   PUGS_INLINE static void
-  convertArgs(ExecutionPolicy::Context& context, const Args&... args)
+  convertArgs(ExecutionPolicy::Context& context, const FlattenList& flatten, const Args&... args)
   {
     static_assert(std::is_same_v<std::tuple<InputType...>, std::tuple<Args...>>, "unexpected input type");
-    _convertArgs(args..., context);
+    _convertArgs(args..., context, flatten, 0);
   }
 
-  PUGS_INLINE static std::function<OutputType(DataVariant&& result)>
-  getResultConverter(ASTNodeDataType data_type)
+  [[nodiscard]] PUGS_INLINE static std::function<OutputType(DataVariant&& result)>
+  getResultConverter(const ASTNodeDataType& data_type)
   {
     switch (data_type) {
     case ASTNodeDataType::list_t: {
diff --git a/src/language/node_processor/BuiltinFunctionProcessor.hpp b/src/language/node_processor/BuiltinFunctionProcessor.hpp
index 3a4b4850384b4fd0ac0d1b4feb49014be1b83b7a..a2c32d5985b14a2c1e5b12e904b764617f5dbcfb 100644
--- a/src/language/node_processor/BuiltinFunctionProcessor.hpp
+++ b/src/language/node_processor/BuiltinFunctionProcessor.hpp
@@ -5,6 +5,7 @@
 #include <language/PEGGrammar.hpp>
 #include <language/node_processor/FunctionArgumentConverter.hpp>
 #include <language/node_processor/INodeProcessor.hpp>
+#include <language/utils/RuntimeError.hpp>
 
 class BuiltinFunctionExpressionProcessor final : public INodeProcessor
 {
@@ -59,8 +60,12 @@ class BuiltinFunctionProcessor : public INodeProcessor
         m_argument_converters[i]->convert(context_exec_policy, std::move(argument_values[i]));
       }
     }
-
-    return m_function_expression_processor->execute(context_exec_policy);
+    try {
+      return m_function_expression_processor->execute(context_exec_policy);
+    }
+    catch (RuntimeError& e) {
+      throw parse_error(e.message(), {m_argument_node.begin()});
+    }
   }
 
   BuiltinFunctionProcessor(ASTNode& argument_node) : m_argument_node{argument_node} {}
diff --git a/src/language/utils/ASTNodeDataTypeTraits.hpp b/src/language/utils/ASTNodeDataTypeTraits.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..14435925d49d1fd42518cef4c74776d79d9bb99d
--- /dev/null
+++ b/src/language/utils/ASTNodeDataTypeTraits.hpp
@@ -0,0 +1,28 @@
+#ifndef AST_NODE_DATA_TYPE_TRAITS_H
+#define AST_NODE_DATA_TYPE_TRAITS_H
+
+#include <algebra/TinyVector.hpp>
+#include <language/ASTNodeDataType.hpp>
+#include <language/FunctionSymbolId.hpp>
+
+template <typename T>
+inline ASTNodeDataType ast_node_data_type_from = ASTNodeDataType::undefined_t;
+
+template <>
+inline ASTNodeDataType ast_node_data_type_from<void> = ASTNodeDataType::void_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<bool> = ASTNodeDataType::bool_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<int64_t> = ASTNodeDataType::int_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<uint64_t> = ASTNodeDataType::unsigned_int_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<double> = ASTNodeDataType::double_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<std::string> = ASTNodeDataType::string_t;
+template <>
+inline ASTNodeDataType ast_node_data_type_from<FunctionSymbolId> = ASTNodeDataType::function_t;
+template <size_t N>
+inline ASTNodeDataType ast_node_data_type_from<TinyVector<N>> = {ASTNodeDataType::vector_t, N};
+
+#endif   // AST_NODE_DATA_TYPE_TRAITS_H
diff --git a/src/language/utils/RuntimeError.hpp b/src/language/utils/RuntimeError.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..b5e2c11a5d5df5f08789581606d894733dbd6d59
--- /dev/null
+++ b/src/language/utils/RuntimeError.hpp
@@ -0,0 +1,27 @@
+#ifndef RUNTIME_ERROR_HPP
+#define RUNTIME_ERROR_HPP
+
+#include <string>
+
+class RuntimeError
+{
+ private:
+  std::string m_message;
+
+ public:
+  const std::string&
+  message() const
+  {
+    return m_message;
+  }
+
+  RuntimeError(const std::string& message) : m_message{message} {}
+
+  RuntimeError()                    = delete;
+  RuntimeError(const RuntimeError&) = delete;
+  RuntimeError(RuntimeError&&)      = delete;
+
+  ~RuntimeError() = default;
+};
+
+#endif   // RUNTIME_ERROR_HPP
diff --git a/src/utils/Exceptions.cpp b/src/utils/Exceptions.cpp
index 85534848f3454e2337685d8ddb1ac81b7ad5d776..1bf598b7ceac54e0cff3d8b2662b35bdc0654e07 100644
--- a/src/utils/Exceptions.cpp
+++ b/src/utils/Exceptions.cpp
@@ -10,7 +10,7 @@ RawError::RawError(std::string_view error_msg) : IExitError(std::string{error_ms
 NormalError::NormalError(std::string_view error_msg)
   : IExitError([&] {
       std::ostringstream os;
-      os << rang::style::bold << "Error:" << rang::style::reset << ' ' << error_msg;
+      os << rang::style::bold << "error:" << rang::style::reset << ' ' << error_msg;
       return os.str();
     }())
 {}
@@ -18,7 +18,7 @@ NormalError::NormalError(std::string_view error_msg)
 UnexpectedError::UnexpectedError(std::string_view error_msg)
   : IBacktraceError([&] {
       std::ostringstream os;
-      os << rang::fgB::red << "Unexpected error:" << rang::style::reset << ' ' << error_msg;
+      os << rang::fgB::red << "unexpected error:" << rang::style::reset << ' ' << error_msg;
       return os.str();
     }())
 {}
@@ -26,7 +26,7 @@ UnexpectedError::UnexpectedError(std::string_view error_msg)
 NotImplementedError::NotImplementedError(std::string_view error_msg)
   : IBacktraceError([&] {
       std::ostringstream os;
-      os << rang::fgB::yellow << "Not implemented yet:" << rang::style::reset << ' ' << error_msg;
+      os << rang::fgB::yellow << "not implemented yet:" << rang::style::reset << ' ' << error_msg;
       return os.str();
     }())
 {}
diff --git a/tests/test_ASTNodeAffectationExpressionBuilder.cpp b/tests/test_ASTNodeAffectationExpressionBuilder.cpp
index dce1fac55f51ea51d21aa5705f2f1b3509c647ee..9f4c26d7fedea9aa60a5c50ad9b15f26b4c62e95 100644
--- a/tests/test_ASTNodeAffectationExpressionBuilder.cpp
+++ b/tests/test_ASTNodeAffectationExpressionBuilder.cpp
@@ -1123,7 +1123,8 @@ let x : R, x=1; x/=2.3;
 
       ast->children.emplace_back(std::make_unique<ASTNode>());
       ast->children.emplace_back(std::make_unique<ASTNode>());
-      REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast}, "invalid implicit conversion: undefined -> Z");
+      REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast},
+                          "unexpected error: invalid implicit conversion: undefined -> Z");
     }
 
     SECTION("Invalid string rhs")
@@ -1135,7 +1136,7 @@ let x : R, x=1; x/=2.3;
       ast->children.emplace_back(std::make_unique<ASTNode>());
       ast->children.emplace_back(std::make_unique<ASTNode>());
       REQUIRE_THROWS_WITH(ASTNodeAffectationExpressionBuilder{*ast},
-                          "invalid implicit conversion: undefined -> string");
+                          "unexpected error: invalid implicit conversion: undefined -> string");
     }
 
     SECTION("Invalid string affectation operator")
diff --git a/tests/test_ASTNodeDataTypeBuilder.cpp b/tests/test_ASTNodeDataTypeBuilder.cpp
index 0d5a3306001e584190dc84101cf324f0f448b802..3f5f361f5677cbb405ec7f8aec2eea402fe50013 100644
--- a/tests/test_ASTNodeDataTypeBuilder.cpp
+++ b/tests/test_ASTNodeDataTypeBuilder.cpp
@@ -241,7 +241,7 @@ let (x,b,n,s) : R*B*N*string;
       std::string_view result = R"(
 (root:void)
  `-(language::var_declaration:typename)
-     +-(language::name_list:void)
+     +-(language::name_list:list)
      |   +-(language::name:x:R)
      |   +-(language::name:b:B)
      |   +-(language::name:n:N)
@@ -663,7 +663,7 @@ let  diff : R, diff = substract(3,2);
      +-(language::name:diff:R)
      `-(language::function_evaluation:R)
          +-(language::name:substract:function)
-         `-(language::function_argument_list:void)
+         `-(language::function_argument_list:list)
              +-(language::integer:3:Z)
              `-(language::integer:2:Z)
 )";
@@ -758,7 +758,7 @@ let s : string, s = cat("foo", "bar");
      +-(language::name:s:string)
      `-(language::function_evaluation:string)
          +-(language::name:cat:function)
-         `-(language::function_argument_list:void)
+         `-(language::function_argument_list:list)
              +-(language::literal:"foo":string)
              `-(language::literal:"bar":string)
 )";
@@ -778,13 +778,13 @@ let (x,x2) : R*R, (x,x2) = x_x2(3);
  +-(language::fct_declaration:void)
  |   `-(language::name:x_x2:function)
  `-(language::var_declaration:typename)
-     +-(language::name_list:void)
+     +-(language::name_list:list)
      |   +-(language::name:x:R)
      |   `-(language::name:x2:R)
      +-(language::type_expression:typename)
      |   +-(language::R_set:typename)
      |   `-(language::R_set:typename)
-     +-(language::name_list:void)
+     +-(language::name_list:list)
      |   +-(language::name:x:R)
      |   `-(language::name:x2:R)
      `-(language::function_evaluation:typename)
diff --git a/tests/test_FunctionTable.cpp b/tests/test_FunctionTable.cpp
index d056f072796e30f06135105e41a9ad93e2d66cdf..5c9d26f39660cb45b0a9f6c423bd2f53636b46b0 100644
--- a/tests/test_FunctionTable.cpp
+++ b/tests/test_FunctionTable.cpp
@@ -15,7 +15,7 @@ TEST_CASE("FunctionTable", "[language]")
 
     std::unique_ptr definition_node = std::make_unique<ASTNode>();
     definition_node->m_data_type    = ASTNodeDataType::double_t;
-    FunctionDescriptor f{std::move(domain_mapping_node), std::move(definition_node)};
+    FunctionDescriptor f{"f", std::move(domain_mapping_node), std::move(definition_node)};
 
     REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t);
     REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::double_t);
@@ -68,7 +68,8 @@ TEST_CASE("FunctionTable", "[language]")
   std::unique_ptr definition_node = std::make_unique<ASTNode>();
   definition_node->m_data_type    = ASTNodeDataType::double_t;
 
-  size_t function_id = table.add(FunctionDescriptor{std::move(domain_mapping_node), std::move(definition_node)});
+  size_t function_id =
+    table.add(FunctionDescriptor{"function", std::move(domain_mapping_node), std::move(definition_node)});
 
   REQUIRE(domain_mapping_node == nullptr);
   REQUIRE(definition_node == nullptr);
@@ -80,10 +81,12 @@ TEST_CASE("FunctionTable", "[language]")
   REQUIRE(const_table.size() == 1);
 
   auto& f = table[function_id];
+  REQUIRE(f.name() == "function");
   REQUIRE(f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t);
   REQUIRE(f.definitionNode().m_data_type == ASTNodeDataType::double_t);
 
   const auto& const_f = const_table[function_id];
+  REQUIRE(const_f.name() == "function");
   REQUIRE(const_f.domainMappingNode().m_data_type == ASTNodeDataType::unsigned_int_t);
   REQUIRE(const_f.definitionNode().m_data_type == ASTNodeDataType::double_t);