diff --git a/src/context/test/CMakeLists.txt b/src/context/test/CMakeLists.txt
index ab775c1da4c3420a58ab2fdad39cc4abbd0a4e7b..3246fe025cfbfa273e467d70c6213bce59e1d86b 100644
--- a/src/context/test/CMakeLists.txt
+++ b/src/context/test/CMakeLists.txt
@@ -27,6 +27,7 @@ SET(CONTEXT_TEST_LIBS
     $<TARGET_OBJECTS:common_time_utils_obj>
     $<TARGET_OBJECTS:common_graph_obj>
     $<TARGET_OBJECTS:common_ft_es_graph_adapter_obj>
+    $<TARGET_OBJECTS:common_ws_common_obj>
     $<TARGET_OBJECTS:util_obj>
     $<TARGET_OBJECTS:context_obj>
     $<TARGET_OBJECTS:expr_visitor_obj>
diff --git a/src/executor/test/CMakeLists.txt b/src/executor/test/CMakeLists.txt
index f2b17693dec199b8e6f688de321b2d40b3b91a89..8eedd7e6dca2c67ff8f2cb29fd9e1210403c98ea 100644
--- a/src/executor/test/CMakeLists.txt
+++ b/src/executor/test/CMakeLists.txt
@@ -31,6 +31,7 @@ SET(EXEC_QUERY_TEST_OBJS
     $<TARGET_OBJECTS:common_http_client_obj>
     $<TARGET_OBJECTS:common_time_utils_obj>
     $<TARGET_OBJECTS:common_ft_es_graph_adapter_obj>
+    $<TARGET_OBJECTS:common_ws_common_obj>
     $<TARGET_OBJECTS:session_obj>
     $<TARGET_OBJECTS:graph_flags_obj>
     $<TARGET_OBJECTS:parser_obj>
diff --git a/src/optimizer/test/CMakeLists.txt b/src/optimizer/test/CMakeLists.txt
index ba3c961f0c0752d096d44de3468bbb09c61d991d..c58b2da6ffd1921a49db356aa5752f2044dd3f7e 100644
--- a/src/optimizer/test/CMakeLists.txt
+++ b/src/optimizer/test/CMakeLists.txt
@@ -29,6 +29,7 @@ set(OPTIMIZER_TEST_LIB
     $<TARGET_OBJECTS:common_time_utils_obj>
     $<TARGET_OBJECTS:common_graph_obj>
     $<TARGET_OBJECTS:common_ft_es_graph_adapter_obj>
+    $<TARGET_OBJECTS:common_ws_common_obj>
     $<TARGET_OBJECTS:idgenerator_obj>
     $<TARGET_OBJECTS:expr_visitor_obj>
     $<TARGET_OBJECTS:session_obj>
diff --git a/src/parser/test/CMakeLists.txt b/src/parser/test/CMakeLists.txt
index 7eba4edd355a2ec3be355a1e36d3666ea1ccb716..bf0da49348256be184c1421461cd3733461e15a2 100644
--- a/src/parser/test/CMakeLists.txt
+++ b/src/parser/test/CMakeLists.txt
@@ -29,6 +29,7 @@ set(PARSER_TEST_LIBS
     $<TARGET_OBJECTS:common_process_obj>
     $<TARGET_OBJECTS:common_time_utils_obj>
     $<TARGET_OBJECTS:common_ft_es_graph_adapter_obj>
+    $<TARGET_OBJECTS:common_ws_common_obj>
     $<TARGET_OBJECTS:session_obj>
     $<TARGET_OBJECTS:graph_flags_obj>
     $<TARGET_OBJECTS:graph_auth_obj>
diff --git a/src/planner/Query.cpp b/src/planner/Query.cpp
index 713d752dc8b925c63e0bc37bf4cc6316f857781e..27c66dd7a02a7ddaf2e360b406b8e0c658ae3304 100644
--- a/src/planner/Query.cpp
+++ b/src/planner/Query.cpp
@@ -7,6 +7,7 @@
 #include "planner/Query.h"
 
 #include <folly/String.h>
+#include <folly/dynamic.h>
 #include <folly/json.h>
 
 #include "util/ToJson.h"
@@ -153,7 +154,14 @@ void Project::clone(const Project &p) {
 
 std::unique_ptr<PlanNodeDescription> Project::explain() const {
     auto desc = SingleInputNode::explain();
-    addDescription("columns", cols_ ? cols_->toString() : "", desc.get());
+    auto columns = folly::dynamic::array();
+    if (cols_) {
+        for (const auto* col : cols_->columns()) {
+            DCHECK(col != nullptr);
+            columns.push_back(col->toString());
+        }
+    }
+    addDescription("columns", folly::toJson(columns), desc.get());
     return desc;
 }
 
diff --git a/src/util/test/CMakeLists.txt b/src/util/test/CMakeLists.txt
index d71c6c17cb0acc9c837683c259aacd722098d8bf..6cc021d50a2ccdfd2070cd71f0adabecc9ee43d8 100644
--- a/src/util/test/CMakeLists.txt
+++ b/src/util/test/CMakeLists.txt
@@ -29,6 +29,7 @@ nebula_add_test(
         $<TARGET_OBJECTS:common_time_utils_obj>
         $<TARGET_OBJECTS:common_graph_obj>
         $<TARGET_OBJECTS:common_ft_es_graph_adapter_obj>
+        $<TARGET_OBJECTS:common_ws_common_obj>
         $<TARGET_OBJECTS:idgenerator_obj>
         $<TARGET_OBJECTS:expr_visitor_obj>
         $<TARGET_OBJECTS:session_obj>
diff --git a/src/validator/test/CMakeLists.txt b/src/validator/test/CMakeLists.txt
index 243bff7349225f2abfa8e7500d7e2d92e33668d9..51dc4be115bc884d76cd5a64e733f685750b3748 100644
--- a/src/validator/test/CMakeLists.txt
+++ b/src/validator/test/CMakeLists.txt
@@ -48,6 +48,7 @@ set(VALIDATOR_TEST_LIBS
     $<TARGET_OBJECTS:common_time_utils_obj>
     $<TARGET_OBJECTS:common_graph_obj>
     $<TARGET_OBJECTS:common_ft_es_graph_adapter_obj>
+    $<TARGET_OBJECTS:common_ws_common_obj>
 )
 
 nebula_add_test(
diff --git a/src/visitor/test/CMakeLists.txt b/src/visitor/test/CMakeLists.txt
index 231eb9b868b14706f1e0e91fc7dfdcb1221d3aea..cb009d7801fcbf5daa3715af3cdf4a54a4895cfa 100644
--- a/src/visitor/test/CMakeLists.txt
+++ b/src/visitor/test/CMakeLists.txt
@@ -49,6 +49,7 @@ nebula_add_test(
         $<TARGET_OBJECTS:common_time_utils_obj>
         $<TARGET_OBJECTS:common_graph_obj>
         $<TARGET_OBJECTS:common_ft_es_graph_adapter_obj>
+        $<TARGET_OBJECTS:common_ws_common_obj>
     LIBRARIES
         gtest
         ${THRIFT_LIBRARIES}