diff --git a/SDK/CPP/private/frame_impl.cpp b/SDK/CPP/private/frame_impl.cpp
index 0b0779b6a2a2d23a3250a0cb917e8486e88af4b9..a91ad3e6a762cf18f9915299df616412e420e2b7 100644
--- a/SDK/CPP/private/frame_impl.cpp
+++ b/SDK/CPP/private/frame_impl.cpp
@@ -50,9 +50,9 @@ voltu::PointCloudPtr FrameImpl::getPointCloud(voltu::PointCloudFormat cloudfmt,
 	return nullptr;
 }
 
-std::vector<std::string> FrameImpl::getMessages()
+std::vector<std::vector<std::string>> FrameImpl::getMessages()
 {
-	std::vector<std::string> msgs;
+	std::vector<std::vector<std::string>> allmsgs;
 
 	for (const auto &fs : framesets_)
 	{
@@ -61,12 +61,13 @@ std::vector<std::string> FrameImpl::getMessages()
 			if (f.hasChannel(ftl::codecs::Channel::Messages))
 			{
 				const auto &m = f.get<std::vector<std::string>>(ftl::codecs::Channel::Messages);
+				auto &msgs = allmsgs.emplace_back();
 				msgs.insert(msgs.end(), m.begin(), m.end());
 			}
 		}
 	}
 
-	return msgs;
+	return allmsgs;
 }
 
 void FrameImpl::pushFrameSet(const std::shared_ptr<ftl::data::FrameSet> &fs)
diff --git a/SDK/CPP/private/frame_impl.hpp b/SDK/CPP/private/frame_impl.hpp
index 1b6074a8a6cc1c23dd9e317c09cf1a5596bd467c..eb5caa5a65b873cc8f80718a1193051abb8fa26a 100644
--- a/SDK/CPP/private/frame_impl.hpp
+++ b/SDK/CPP/private/frame_impl.hpp
@@ -20,7 +20,7 @@ public:
 
 	voltu::PointCloudPtr getPointCloud(voltu::PointCloudFormat cloudfmt, voltu::PointFormat pointfmt) override;
 
-	std::vector<std::string> getMessages() override;
+	std::vector<std::vector<std::string>> getMessages() override;
 
 	int64_t getTimestamp() override;
 
diff --git a/SDK/CPP/public/include/voltu/types/frame.hpp b/SDK/CPP/public/include/voltu/types/frame.hpp
index 4209cc80c2d1af4e46c4c1d7227ad0e3a9918c79..30b7c4ddcf26c22256700311457abaf6755b8ef6 100644
--- a/SDK/CPP/public/include/voltu/types/frame.hpp
+++ b/SDK/CPP/public/include/voltu/types/frame.hpp
@@ -26,7 +26,7 @@ public:
 
 	PY_API PY_RV_LIFETIME_PARENT virtual voltu::PointCloudPtr getPointCloud(voltu::PointCloudFormat cloudfmt, voltu::PointFormat pointfmt) = 0;
 
-	PY_API virtual std::vector<std::string> getMessages() = 0;
+	PY_API virtual std::vector<std::vector<std::string>> getMessages() = 0;
 
 	PY_API virtual int64_t getTimestamp() = 0;
 };
diff --git a/SDK/CPP/public/include/voltu/voltu.hpp b/SDK/CPP/public/include/voltu/voltu.hpp
index a2c4c0a142341a9c145999bc1cadd530271c25b7..d3e1413b4052c065709aaa7591a9c93d37e7550d 100644
--- a/SDK/CPP/public/include/voltu/voltu.hpp
+++ b/SDK/CPP/public/include/voltu/voltu.hpp
@@ -8,7 +8,7 @@
 
 // Bump these for each release
 #define VOLTU_VERSION_MAJOR 0    // For API incompatible changes
-#define VOLTU_VERSION_MINOR 2    // For binary compatibility and extensions
+#define VOLTU_VERSION_MINOR 3    // For binary compatibility and extensions
 #define VOLTU_VERSION_PATCH 0    // Binary compatible internal fixes
 
 #define VOLTU_VERSION ((VOLTU_VERSION_MAJOR*10000) + (VOLTU_VERSION_MINOR*100) + VOLTU_VERSION_PATCH)
diff --git a/SDK/CPP/public/samples/fusion_evaluator/main.cpp b/SDK/CPP/public/samples/fusion_evaluator/main.cpp
index 7eebe3461965ff15804aec51cef0592e9717caa5..06d7567abe8be27daf0ecefddea5cc137ffadb4a 100644
--- a/SDK/CPP/public/samples/fusion_evaluator/main.cpp
+++ b/SDK/CPP/public/samples/fusion_evaluator/main.cpp
@@ -102,10 +102,12 @@ int main(int argc, char **argv)
 		break;
 	}
 
-	std::vector<std::string> msgs = frame->getMessages();
-	for (const auto &s : msgs)
-	{
-		cout << s << endl;
+	std::vector<std::vector<std::string>> msgs = frame->getMessages();
+	if (msgs.size() > 0) {
+		for (const auto &s : msgs[0])
+		{
+			cout << s << endl;
+		}
 	}
 
 	cv::waitKey(-1);
diff --git a/components/operators/src/analysis/evaluation/gt_analysis.cpp b/components/operators/src/analysis/evaluation/gt_analysis.cpp
index b80d2beba2fdab6ffb93d887259eb297f786f1d3..23c8b25baf3cbf8e66ddbc820c725643ae98c86b 100644
--- a/components/operators/src/analysis/evaluation/gt_analysis.cpp
+++ b/components/operators/src/analysis/evaluation/gt_analysis.cpp
@@ -113,6 +113,8 @@ bool GTAnalysis::apply(ftl::rgbd::Frame &in, ftl::rgbd::Frame &out, cudaStream_t
 			);
 		}
 
+		cudaStreamSynchronize(stream);
+
 		cudaMemcpy(&err, output_, sizeof(err), cudaMemcpyDeviceToHost);
 		msgs.push_back(" ");
 		if (use_disp) 	{ report(msgs, err, o, npixels, "px", 1.0); }
diff --git a/components/operators/src/fusion/carving/carver.cu b/components/operators/src/fusion/carving/carver.cu
index 1fc2013e0a7cdc862da4b243bfcfcf27582c7ec3..497cf848e4fa8a7c4e17e6bc54692d2ce8fa71cb 100644
--- a/components/operators/src/fusion/carving/carver.cu
+++ b/components/operators/src/fusion/carving/carver.cu
@@ -74,8 +74,7 @@ __global__ void reverse_check_kernel(
 
 	float d = depth_in[y*pitch4+x];
 
-	// TODO: Externally provide the error coefficient
-	const float err_coef = 0.0005f; //depthErrorCoef(ointrin);
+	const float err_coef = depthErrorCoef(ointrin);
 
 	int ox = 0;
 	int oy = 0;
@@ -95,7 +94,7 @@ __global__ void reverse_check_kernel(
 			// TODO: Threshold comes from depth error characteristics
 			// If the value is significantly further then carve. Depth error
 			// is not always easy to calculate, depends on source.
-			// FIXME: Use length between 3D points, not depth
+			// FIXME: Use length between 3D points, not depth?
 			if (!(d2 < ointrin.maxDepth && d2 - campos.z > d2*d2*err_coef)) {
 				match = fabsf(campos.z - d2) < d2*d2*err_coef; break;
 			}