diff --git a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
index 8ceb55a54ac1dada53f69c20bdf546c42f954320..77abdcf0305a0f9482837ca664a90a3a9d661841 100644
--- a/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeBuiltinFunctionExpressionBuilder.cpp
@@ -112,29 +112,7 @@ ASTNodeBuiltinFunctionExpressionBuilder::_getArgumentConverter(const ASTNodeData
   };
 
   auto get_function_argument_to_string_converter = [&]() -> std::unique_ptr<IFunctionArgumentConverter> {
-    switch (argument_node_sub_data_type.m_data_type) {
-    case ASTNodeDataType::bool_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, bool>>(argument_number);
-    }
-    case ASTNodeDataType::unsigned_int_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, uint64_t>>(argument_number);
-    }
-    case ASTNodeDataType::int_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, int64_t>>(argument_number);
-    }
-    case ASTNodeDataType::double_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, double>>(argument_number);
-    }
-    case ASTNodeDataType::string_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, std::string>>(argument_number);
-    }
-      // LCOV_EXCL_START
-    default: {
-      throw parse_error("unexpected error: invalid argument type for function",
-                        std::vector{argument_node_sub_data_type.m_parent_node.begin()});
-    }
-      // LCOV_EXCL_STOP
-    }
+    return std::make_unique<FunctionArgumentToStringConverter>(argument_number);
   };
 
   auto get_function_argument_to_type_id_converter = [&]() -> std::unique_ptr<IFunctionArgumentConverter> {
diff --git a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
index 027c3020f8b205757f7ea531936d8b282689831d..f2369940873394a33db2718a7ff42fe4870cffc2 100644
--- a/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
+++ b/src/language/ast/ASTNodeFunctionExpressionBuilder.cpp
@@ -84,29 +84,7 @@ ASTNodeFunctionExpressionBuilder::_getArgumentConverter(SymbolType& parameter_sy
   };
 
   auto get_function_argument_converter_for_string = [&]() -> std::unique_ptr<IFunctionArgumentConverter> {
-    switch (node_sub_data_type.m_data_type) {
-    case ASTNodeDataType::bool_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, bool>>(parameter_id);
-    }
-    case ASTNodeDataType::unsigned_int_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, uint64_t>>(parameter_id);
-    }
-    case ASTNodeDataType::int_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, int64_t>>(parameter_id);
-    }
-    case ASTNodeDataType::double_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, double>>(parameter_id);
-    }
-    case ASTNodeDataType::string_t: {
-      return std::make_unique<FunctionArgumentConverter<std::string, std::string>>(parameter_id);
-    }
-      // LCOV_EXCL_START
-    default: {
-      throw parse_error("unexpected error: invalid argument type",
-                        std::vector{node_sub_data_type.m_parent_node.begin()});
-    }
-      // LCOV_EXCL_STOP
-    }
+    return std::make_unique<FunctionArgumentToStringConverter>(parameter_id);
   };
 
   auto get_function_argument_converter_for_parameter_type = [&]() {
diff --git a/src/language/node_processor/FunctionArgumentConverter.hpp b/src/language/node_processor/FunctionArgumentConverter.hpp
index afd4373ce8dedb5cf460e77c6d4b9ba7e30035fc..4bf7e56eebfd93b244d13a774e2e69aac2834794 100644
--- a/src/language/node_processor/FunctionArgumentConverter.hpp
+++ b/src/language/node_processor/FunctionArgumentConverter.hpp
@@ -7,6 +7,8 @@
 #include <utils/Exceptions.hpp>
 #include <utils/PugsTraits.hpp>
 
+#include <sstream>
+
 class IFunctionArgumentConverter
 {
  public:
@@ -20,6 +22,24 @@ class IFunctionArgumentConverter
   virtual ~IFunctionArgumentConverter() = default;
 };
 
+class FunctionArgumentToStringConverter final : public IFunctionArgumentConverter
+{
+ private:
+  size_t m_argument_id;
+
+ public:
+  DataVariant
+  convert(ExecutionPolicy& exec_policy, DataVariant&& value)
+  {
+    std::ostringstream sout;
+    sout << value;
+    exec_policy.currentContext()[m_argument_id] = sout.str();
+    return {};
+  }
+
+  FunctionArgumentToStringConverter(size_t argument_id) : m_argument_id{argument_id} {}
+};
+
 template <typename ExpectedValueType, typename ProvidedValueType>
 class FunctionArgumentConverter final : public IFunctionArgumentConverter
 {
@@ -30,10 +50,9 @@ class FunctionArgumentConverter final : public IFunctionArgumentConverter
   DataVariant
   convert(ExecutionPolicy& exec_policy, DataVariant&& value)
   {
+    static_assert(not std::is_same_v<ExpectedValueType, std::string>, "use FunctionArgumentToStringConverter");
     if constexpr (std::is_same_v<ExpectedValueType, ProvidedValueType>) {
       exec_policy.currentContext()[m_argument_id] = std::move(value);
-    } else if constexpr (std::is_same_v<ExpectedValueType, std::string>) {
-      exec_policy.currentContext()[m_argument_id] = std::move(std::to_string(std::get<ProvidedValueType>(value)));
     } else {
       exec_policy.currentContext()[m_argument_id] =
         std::move(static_cast<ExpectedValueType>(std::get<ProvidedValueType>(value)));