mojo::Serialize*_() calls now propogate/return validation errors.

The public-facing API can use these, but will probably want to use a separate enum of errors (since ValidationError is namespace'd as internal, and should probably remain so).  For now, a public serialization API can return a boolean.

R=viettrungluu@chromium.org
CC=jamesr@chromium.org
BUG=

Review URL: https://codereview.chromium.org/1387993002 .
diff --git a/mojo/public/cpp/bindings/lib/array_serialization.h b/mojo/public/cpp/bindings/lib/array_serialization.h
index dc98245..effec05 100644
--- a/mojo/public/cpp/bindings/lib/array_serialization.h
+++ b/mojo/public/cpp/bindings/lib/array_serialization.h
@@ -45,32 +45,38 @@
   }
 
   template <typename Iterator>
-  static void SerializeElements(Iterator it,
-                                size_t num_elements,
-                                Buffer* buf,
-                                Array_Data<F>* output,
-                                const ArrayValidateParams* validate_params) {
+  static ValidationError SerializeElements(
+      Iterator it,
+      size_t num_elements,
+      Buffer* buf,
+      Array_Data<F>* output,
+      const ArrayValidateParams* validate_params) {
     MOJO_DCHECK(!validate_params->element_is_nullable)
         << "Primitive type should be non-nullable";
     MOJO_DCHECK(!validate_params->element_validate_params)
         << "Primitive type should not have array validate params";
     for (size_t i = 0; i < num_elements; ++i, ++it)
       output->at(i) = *it;
+
+    return VALIDATION_ERROR_NONE;
   }
 
   // We can optimize serializing PODs by |memcpy|ing directly.
   // Note that this has precedence over its templated sibling defined above.
-  static void SerializeElements(typename Array<E>::Iterator it,
-                                size_t num_elements,
-                                Buffer* buf,
-                                Array_Data<F>* output,
-                                const ArrayValidateParams* validate_params) {
+  static ValidationError SerializeElements(
+      typename Array<E>::Iterator it,
+      size_t num_elements,
+      Buffer* buf,
+      Array_Data<F>* output,
+      const ArrayValidateParams* validate_params) {
     MOJO_DCHECK(!validate_params->element_is_nullable)
         << "Primitive type should be non-nullable";
     MOJO_DCHECK(!validate_params->element_validate_params)
         << "Primitive type should not have array validate params";
     if (num_elements)
       memcpy(output->storage(), &(*it), num_elements * sizeof(E));
+
+    return VALIDATION_ERROR_NONE;
   }
 
   static void DeserializeElements(Array_Data<F>* input, Array<E>* output) {
@@ -89,11 +95,12 @@
   }
 
   template <typename Iterator>
-  static void SerializeElements(Iterator it,
-                                size_t num_elements,
-                                Buffer* buf,
-                                Array_Data<bool>* output,
-                                const ArrayValidateParams* validate_params) {
+  static ValidationError SerializeElements(
+      Iterator it,
+      size_t num_elements,
+      Buffer* buf,
+      Array_Data<bool>* output,
+      const ArrayValidateParams* validate_params) {
     MOJO_DCHECK(!validate_params->element_is_nullable)
         << "Primitive type should be non-nullable";
     MOJO_DCHECK(!validate_params->element_validate_params)
@@ -102,6 +109,8 @@
     // TODO(darin): Can this be a memcpy somehow instead of a bit-by-bit copy?
     for (size_t i = 0; i < num_elements; ++i, ++it)
       output->at(i) = *it;
+
+    return VALIDATION_ERROR_NONE;
   }
 
   static void DeserializeElements(Array_Data<bool>* input,
@@ -122,24 +131,29 @@
   }
 
   template <typename Iterator>
-  static void SerializeElements(Iterator it,
-                                size_t num_elements,
-                                Buffer* buf,
-                                Array_Data<H>* output,
-                                const ArrayValidateParams* validate_params) {
+  static ValidationError SerializeElements(
+      Iterator it,
+      size_t num_elements,
+      Buffer* buf,
+      Array_Data<H>* output,
+      const ArrayValidateParams* validate_params) {
     MOJO_DCHECK(!validate_params->element_validate_params)
         << "Handle type should not have array validate params";
 
     for (size_t i = 0; i < num_elements; ++i, ++it) {
       // Transfer ownership of the handle.
       output->at(i) = it->release();
-      MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
-          !validate_params->element_is_nullable && !output->at(i).is_valid(),
-          VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
-          MakeMessageWithArrayIndex(
-              "invalid handle in array expecting valid handles", num_elements,
-              i));
+      if (!validate_params->element_is_nullable && !output->at(i).is_valid()) {
+        MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+            VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
+            MakeMessageWithArrayIndex(
+                "invalid handle in array expecting valid handles", num_elements,
+                i));
+        return VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE;
+      }
     }
+
+    return VALIDATION_ERROR_NONE;
   }
 
   static void DeserializeElements(Array_Data<H>* input,
@@ -171,22 +185,30 @@
   }
 
   template <typename Iterator>
-  static void SerializeElements(Iterator it,
-                                size_t num_elements,
-                                Buffer* buf,
-                                Array_Data<S_Data*>* output,
-                                const ArrayValidateParams* validate_params) {
+  static ValidationError SerializeElements(
+      Iterator it,
+      size_t num_elements,
+      Buffer* buf,
+      Array_Data<S_Data*>* output,
+      const ArrayValidateParams* validate_params) {
     for (size_t i = 0; i < num_elements; ++i, ++it) {
       S_Data* element;
-      SerializeCaller::Run(&(*it), buf, &element,
-                           validate_params->element_validate_params);
+      auto retval = SerializeCaller::Run(
+          &(*it), buf, &element, validate_params->element_validate_params);
+      if (retval != VALIDATION_ERROR_NONE)
+        return retval;
+
       output->at(i) = element;
-      MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
-          !validate_params->element_is_nullable && !element,
-          VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
-          MakeMessageWithArrayIndex("null in array expecting valid pointers",
-                                    num_elements, i));
+      if (!validate_params->element_is_nullable && !element) {
+        MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+            VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+            MakeMessageWithArrayIndex("null in array expecting valid pointers",
+                                      num_elements, i));
+        return VALIDATION_ERROR_UNEXPECTED_NULL_POINTER;
+      }
     }
+
+    return VALIDATION_ERROR_NONE;
   }
 
   static void DeserializeElements(Array_Data<S_Data*>* input,
@@ -208,41 +230,42 @@
     // takes precedence over the |String|-overloaded Run() below.
     template <typename T,
               typename = typename EnableIf<!IsSame<T, String>::value, T>::type>
-    static void Run(T* input,
-                    Buffer* buf,
-                    typename WrapperTraits<T>::DataType* output,
-                    const ArrayValidateParams* validate_params) {
+    static ValidationError Run(T* input,
+                               Buffer* buf,
+                               typename WrapperTraits<T>::DataType* output,
+                               const ArrayValidateParams* validate_params) {
       MOJO_DCHECK(!validate_params)
           << "Struct type should not have array validate params";
-      Serialize_(UnwrapStructPtr<T>::value(*input), buf, output);
+      return Serialize_(UnwrapStructPtr<T>::value(*input), buf, output);
     }
 
-    static void Run(const String* input,
-                    Buffer* buf,
-                    String_Data** output,
-                    const ArrayValidateParams* validate_params) {
+    static ValidationError Run(const String* input,
+                               Buffer* buf,
+                               String_Data** output,
+                               const ArrayValidateParams* validate_params) {
       MOJO_DCHECK(validate_params &&
                   !validate_params->element_validate_params &&
                   !validate_params->element_is_nullable &&
                   validate_params->expected_num_elements == 0)
           << "String type has unexpected array validate params";
       SerializeString_(*input, buf, output);
+      return VALIDATION_ERROR_NONE;
     }
 
     template <typename T>
-    static void Run(Array<T>* input,
-                    Buffer* buf,
-                    typename Array<T>::Data_** output,
-                    const ArrayValidateParams* validate_params) {
-      SerializeArray_(input, buf, output, validate_params);
+    static ValidationError Run(Array<T>* input,
+                               Buffer* buf,
+                               typename Array<T>::Data_** output,
+                               const ArrayValidateParams* validate_params) {
+      return SerializeArray_(input, buf, output, validate_params);
     }
 
     template <typename Key, typename Value>
-    static void Run(Map<Key, Value>* input,
-                    Buffer* buf,
-                    typename Map<Key, Value>::Data_** output,
-                    const ArrayValidateParams* validate_params) {
-      SerializeMap_(input, buf, output, validate_params);
+    static ValidationError Run(Map<Key, Value>* input,
+                               Buffer* buf,
+                               typename Map<Key, Value>::Data_** output,
+                               const ArrayValidateParams* validate_params) {
+      return SerializeMap_(input, buf, output, validate_params);
     }
   };
 
@@ -287,20 +310,28 @@
   }
 
   template <typename Iterator>
-  static void SerializeElements(Iterator it,
-                                size_t num_elements,
-                                Buffer* buf,
-                                Array_Data<U_Data>* output,
-                                const ArrayValidateParams* validate_params) {
+  static ValidationError SerializeElements(
+      Iterator it,
+      size_t num_elements,
+      Buffer* buf,
+      Array_Data<U_Data>* output,
+      const ArrayValidateParams* validate_params) {
     for (size_t i = 0; i < num_elements; ++i, ++it) {
       U_Data* result = output->storage() + i;
-      SerializeUnion_(it->get(), buf, &result, true);
-      MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
-          !validate_params->element_is_nullable && output->at(i).is_null(),
-          VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
-          MakeMessageWithArrayIndex("null in array expecting valid unions",
-                                    num_elements, i));
+      auto retval = SerializeUnion_(it->get(), buf, &result, true);
+      if (retval != VALIDATION_ERROR_NONE)
+        return retval;
+      if (!validate_params->element_is_nullable && output->at(i).is_null()) {
+        MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
+
+            VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
+            MakeMessageWithArrayIndex("null in array expecting valid unions",
+                                      num_elements, i));
+        return VALIDATION_ERROR_UNEXPECTED_NULL_POINTER;
+      }
     }
+
+    return VALIDATION_ERROR_NONE;
   }
 
   static void DeserializeElements(Array_Data<U_Data>* input, Array<U>* output) {
@@ -327,32 +358,43 @@
   return internal::ArraySerializer<E, F>::GetSerializedSize(input);
 }
 
+// SerializeArray_ will return VALIDATION_ERROR_NONE on success and set
+// |output| accordingly.  On failure, |input| will be partially serialized into
+// |output| up until an error occurs (which is propagated up and returned by
+// SerializeArray_), in which case |buf| is also partially consumed.
 template <typename E, typename F>
-inline void SerializeArray_(
+inline internal::ValidationError SerializeArray_(
     Array<E>* input,
     internal::Buffer* buf,
     internal::Array_Data<F>** output,
     const internal::ArrayValidateParams* validate_params) {
   MOJO_DCHECK(input);
-  if (*input) {
+  if (!*input) {
+    // It is up to the caller to make sure the given |Array| is not null if it
+    // is not nullable.
+    *output = nullptr;
+    return internal::VALIDATION_ERROR_NONE;
+  }
+
+  if (validate_params->expected_num_elements != 0 &&
+      input->size() != validate_params->expected_num_elements) {
     MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
-        validate_params->expected_num_elements != 0 &&
-            input->size() != validate_params->expected_num_elements,
         internal::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER,
         internal::MakeMessageWithExpectedArraySize(
             "fixed-size array has wrong number of elements", input->size(),
             validate_params->expected_num_elements));
-
-    internal::Array_Data<F>* result =
-        internal::Array_Data<F>::New(input->size(), buf);
-    if (result) {
-      internal::ArraySerializer<E, F>::SerializeElements(
-          input->begin(), input->size(), buf, result, validate_params);
-    }
-    *output = result;
-  } else {
-    *output = nullptr;
+    return internal::ValidationError::VALIDATION_ERROR_UNEXPECTED_ARRAY_HEADER;
   }
+
+  internal::Array_Data<F>* result =
+      internal::Array_Data<F>::New(input->size(), buf);
+  auto retval = internal::ArraySerializer<E, F>::SerializeElements(
+      input->begin(), input->size(), buf, result, validate_params);
+  if (retval != internal::VALIDATION_ERROR_NONE)
+    return retval;
+
+  *output = result;
+  return internal::VALIDATION_ERROR_NONE;
 }
 
 template <typename E, typename F>
diff --git a/mojo/public/cpp/bindings/lib/control_message_handler.cc b/mojo/public/cpp/bindings/lib/control_message_handler.cc
index 0c46982..6cc9568 100644
--- a/mojo/public/cpp/bindings/lib/control_message_handler.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_handler.cc
@@ -56,7 +56,10 @@
   ResponseMessageBuilder builder(kRunMessageId, size, message->request_id());
 
   RunResponseMessageParams_Data* response_params = nullptr;
-  Serialize_(response_params_ptr.get(), builder.buffer(), &response_params);
+  auto result =
+      Serialize_(response_params_ptr.get(), builder.buffer(), &response_params);
+  MOJO_DCHECK(result == VALIDATION_ERROR_NONE);
+
   response_params->EncodePointersAndHandles(
       builder.message()->mutable_handles());
   bool ok = responder->Accept(builder.message());
diff --git a/mojo/public/cpp/bindings/lib/control_message_proxy.cc b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
index ee1e695..c2f4594 100644
--- a/mojo/public/cpp/bindings/lib/control_message_proxy.cc
+++ b/mojo/public/cpp/bindings/lib/control_message_proxy.cc
@@ -52,7 +52,9 @@
   RequestMessageBuilder builder(kRunMessageId, size);
 
   RunMessageParams_Data* params = nullptr;
-  Serialize_(params_ptr.get(), builder.buffer(), &params);
+  auto result = Serialize_(params_ptr.get(), builder.buffer(), &params);
+  MOJO_DCHECK(result == VALIDATION_ERROR_NONE);
+
   params->EncodePointersAndHandles(builder.message()->mutable_handles());
   MessageReceiver* responder = new RunResponseForwardToCallback(callback);
   if (!receiver->AcceptWithResponder(builder.message(), responder))
@@ -70,7 +72,9 @@
   MessageBuilder builder(kRunOrClosePipeMessageId, size);
 
   RunOrClosePipeMessageParams_Data* params = nullptr;
-  Serialize_(params_ptr.get(), builder.buffer(), &params);
+  auto result = Serialize_(params_ptr.get(), builder.buffer(), &params);
+  MOJO_DCHECK(result == VALIDATION_ERROR_NONE);
+
   params->EncodePointersAndHandles(builder.message()->mutable_handles());
   bool ok = receiver->Accept(builder.message());
   MOJO_ALLOW_UNUSED_LOCAL(ok);
diff --git a/mojo/public/cpp/bindings/lib/map_serialization.h b/mojo/public/cpp/bindings/lib/map_serialization.h
index 8ef83b3..3f24b1a 100644
--- a/mojo/public/cpp/bindings/lib/map_serialization.h
+++ b/mojo/public/cpp/bindings/lib/map_serialization.h
@@ -121,6 +121,11 @@
          value_data_size;
 }
 
+// SerializeMap_ will return VALIDATION_ERROR_NONE on success and set
+// |output| accordingly.  On failure, |input| will be partially serialized into
+// |output| up until an error occurs (which is propagated up and returned by
+// SerializeMap_), in which case |buf| is also partially consumed.
+//
 // We don't need an ArrayValidateParams instance for key validation since
 // we can deduce it from the Key type. (which can only be primitive types or
 // non-nullable strings.)
@@ -128,45 +133,54 @@
           typename MapValue,
           typename DataKey,
           typename DataValue>
-inline void SerializeMap_(
+inline internal::ValidationError SerializeMap_(
     Map<MapKey, MapValue>* input,
     internal::Buffer* buf,
     internal::Map_Data<DataKey, DataValue>** output,
     const internal::ArrayValidateParams* value_validate_params) {
-  if (input && *input) {
-    internal::Map_Data<DataKey, DataValue>* result =
-        internal::Map_Data<DataKey, DataValue>::New(buf);
-    internal::Array_Data<DataKey>* keys_data =
-        internal::Array_Data<DataKey>::New(input->size(), buf);
+  if (input->is_null()) {
+    // |input| could be a nullable map, in which case |output| is serialized as
+    // null, which is valid.
+    *output = nullptr;
+    return internal::VALIDATION_ERROR_NONE;
+  }
 
-    if (result && keys_data) {
-      result->keys.ptr = keys_data;
+  internal::Map_Data<DataKey, DataValue>* result =
+      internal::Map_Data<DataKey, DataValue>::New(buf);
 
-      // We *must* serialize the keys before we allocate an Array_Data for the
-      // values.
-      internal::MapKeyIterator<MapKey, MapValue> key_iter(input);
-      const internal::ArrayValidateParams* key_validate_params =
-          internal::MapKeyValidateParamsFactory<DataKey>::Get();
+  // We *must* serialize the keys before we allocate an Array_Data for the
+  // values.
+  internal::Array_Data<DataKey>* keys_data =
+      internal::Array_Data<DataKey>::New(input->size(), buf);
+  result->keys.ptr = keys_data;
 
+  internal::MapKeyIterator<MapKey, MapValue> key_iter(input);
+  const internal::ArrayValidateParams* key_validate_params =
+      internal::MapKeyValidateParamsFactory<DataKey>::Get();
+
+  auto keys_retval =
       internal::ArraySerializer<MapKey, DataKey>::SerializeElements(
           key_iter.begin(), input->size(), buf, result->keys.ptr,
           key_validate_params);
+  if (keys_retval != internal::VALIDATION_ERROR_NONE)
+    return keys_retval;
 
-      // Now we try allocate an Array_Data for the values
-      internal::Array_Data<DataValue>* values_data =
-          internal::Array_Data<DataValue>::New(input->size(), buf);
-      if (values_data) {
-        result->values.ptr = values_data;
-        internal::MapValueIterator<MapKey, MapValue> value_iter(input);
-        internal::ArraySerializer<MapValue, DataValue>::SerializeElements(
-            value_iter.begin(), input->size(), buf, result->values.ptr,
-            value_validate_params);
-      }
-    }
-    *output = result;
-  } else {
-    *output = nullptr;
-  }
+  // Now we try allocate an Array_Data for the values
+  internal::Array_Data<DataValue>* values_data =
+      internal::Array_Data<DataValue>::New(input->size(), buf);
+  result->values.ptr = values_data;
+
+  internal::MapValueIterator<MapKey, MapValue> value_iter(input);
+
+  auto values_retval =
+      internal::ArraySerializer<MapValue, DataValue>::SerializeElements(
+          value_iter.begin(), input->size(), buf, result->values.ptr,
+          value_validate_params);
+  if (values_retval != internal::VALIDATION_ERROR_NONE)
+    return values_retval;
+
+  *output = result;
+  return internal::VALIDATION_ERROR_NONE;
 }
 
 template <typename MapKey,
diff --git a/mojo/public/cpp/bindings/lib/map_serialization_forward.h b/mojo/public/cpp/bindings/lib/map_serialization_forward.h
index 40f6e8e..e6cd69f 100644
--- a/mojo/public/cpp/bindings/lib/map_serialization_forward.h
+++ b/mojo/public/cpp/bindings/lib/map_serialization_forward.h
@@ -26,10 +26,11 @@
           typename MapValue,
           typename DataKey,
           typename DataValue>
-void SerializeMap_(Map<MapKey, MapValue>* input,
-                   internal::Buffer* buf,
-                   internal::Map_Data<DataKey, DataValue>** output,
-                   const internal::ArrayValidateParams* value_validate_params);
+internal::ValidationError SerializeMap_(
+    Map<MapKey, MapValue>* input,
+    internal::Buffer* buf,
+    internal::Map_Data<DataKey, DataValue>** output,
+    const internal::ArrayValidateParams* value_validate_params);
 template <typename MapKey, typename MapValue>
 size_t GetSerializedSize_(const Map<MapKey, MapValue>& input);
 
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.cc b/mojo/public/cpp/bindings/lib/validation_errors.cc
index aa5f97a..4137ba1 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.cc
+++ b/mojo/public/cpp/bindings/lib/validation_errors.cc
@@ -11,8 +11,6 @@
 namespace {
 
 ValidationErrorObserverForTesting* g_validation_error_observer = nullptr;
-SerializationWarningObserverForTesting* g_serialization_warning_observer =
-    nullptr;
 
 }  // namespace
 
@@ -73,26 +71,5 @@
   g_validation_error_observer = nullptr;
 }
 
-bool ReportSerializationWarning(ValidationError error) {
-  if (g_serialization_warning_observer) {
-    g_serialization_warning_observer->set_last_warning(error);
-    return true;
-  }
-
-  return false;
-}
-
-SerializationWarningObserverForTesting::SerializationWarningObserverForTesting()
-    : last_warning_(VALIDATION_ERROR_NONE) {
-  MOJO_DCHECK(!g_serialization_warning_observer);
-  g_serialization_warning_observer = this;
-}
-
-SerializationWarningObserverForTesting::
-    ~SerializationWarningObserverForTesting() {
-  MOJO_DCHECK(g_serialization_warning_observer == this);
-  g_serialization_warning_observer = nullptr;
-}
-
 }  // namespace internal
 }  // namespace mojo
diff --git a/mojo/public/cpp/bindings/lib/validation_errors.h b/mojo/public/cpp/bindings/lib/validation_errors.h
index 43059c2..953ab5e 100644
--- a/mojo/public/cpp/bindings/lib/validation_errors.h
+++ b/mojo/public/cpp/bindings/lib/validation_errors.h
@@ -78,45 +78,13 @@
   MOJO_DISALLOW_COPY_AND_ASSIGN(ValidationErrorObserverForTesting);
 };
 
-// Used only by MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING. Don't use it directly.
-//
-// The function returns true if the error is recorded (by a
-// SerializationWarningObserverForTesting object), false otherwise.
-bool ReportSerializationWarning(ValidationError error);
-
-// Only used by serialization tests and when there is only one thread doing
-// message serialization.
-class SerializationWarningObserverForTesting {
- public:
-  SerializationWarningObserverForTesting();
-  ~SerializationWarningObserverForTesting();
-
-  ValidationError last_warning() const { return last_warning_; }
-  void set_last_warning(ValidationError error) { last_warning_ = error; }
-
- private:
-  ValidationError last_warning_;
-
-  MOJO_DISALLOW_COPY_AND_ASSIGN(SerializationWarningObserverForTesting);
-};
-
 }  // namespace internal
 }  // namespace mojo
 
-// In debug build, logs a serialization warning if |condition| evaluates to
-// true:
-//   - if there is a SerializationWarningObserverForTesting object alive,
-//     records |error| in it;
-//   - otherwise, logs a fatal-level message.
-// |error| is the validation error that will be triggered by the receiver
-// of the serialzation result.
-//
-// In non-debug build, does nothing (not even compiling |condition|).
-#define MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(                        \
-    condition, error, description)                                       \
-  MOJO_DLOG_IF(FATAL, (condition) && !ReportSerializationWarning(error)) \
-      << "The outgoing message will trigger "                            \
-      << ValidationErrorToString(error) << " at the receiving side ("    \
-      << description << ").";
+// In a debug build, logs a serialization warning.
+#define MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(error, description) \
+  MOJO_DLOG(WARNING) << "The outgoing message will trigger "         \
+                     << ValidationErrorToString(error)               \
+                     << " at the receiving side (" << description << ")."
 
 #endif  // MOJO_PUBLIC_CPP_BINDINGS_LIB_VALIDATION_ERRORS_H_
diff --git a/mojo/public/cpp/bindings/tests/array_unittest.cc b/mojo/public/cpp/bindings/tests/array_unittest.cc
index ffee9cc..3eecd52 100644
--- a/mojo/public/cpp/bindings/tests/array_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/array_unittest.cc
@@ -161,7 +161,8 @@
   FixedBufferForTesting buf(size);
   Array_Data<int32_t>* data;
   ArrayValidateParams validate_params(0, false, nullptr);
-  SerializeArray_(&array, &buf, &data, &validate_params);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            SerializeArray_(&array, &buf, &data, &validate_params));
 
   Array<int32_t> array2;
   Deserialize_(data, &array2);
@@ -179,7 +180,8 @@
   FixedBufferForTesting buf(size);
   Array_Data<int32_t>* data;
   ArrayValidateParams validate_params(0, false, nullptr);
-  SerializeArray_(&array, &buf, &data, &validate_params);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            SerializeArray_(&array, &buf, &data, &validate_params));
 
   Array<int32_t> array2;
   Deserialize_(data, &array2);
@@ -202,7 +204,8 @@
   Array_Data<Array_Data<int32_t>*>* data;
   ArrayValidateParams validate_params(
       0, false, new ArrayValidateParams(0, false, nullptr));
-  SerializeArray_(&array, &buf, &data, &validate_params);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            SerializeArray_(&array, &buf, &data, &validate_params));
 
   Array<Array<int32_t>> array2;
   Deserialize_(data, &array2);
@@ -227,7 +230,8 @@
   FixedBufferForTesting buf(size);
   Array_Data<bool>* data;
   ArrayValidateParams validate_params(0, false, nullptr);
-  SerializeArray_(&array, &buf, &data, &validate_params);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            SerializeArray_(&array, &buf, &data, &validate_params));
 
   Array<bool> array2;
   Deserialize_(data, &array2);
@@ -255,7 +259,8 @@
   Array_Data<String_Data*>* data;
   ArrayValidateParams validate_params(
       0, false, new ArrayValidateParams(0, false, nullptr));
-  SerializeArray_(&array, &buf, &data, &validate_params);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            SerializeArray_(&array, &buf, &data, &validate_params));
 
   Array<String> array2;
   Deserialize_(data, &array2);
diff --git a/mojo/public/cpp/bindings/tests/map_unittest.cc b/mojo/public/cpp/bindings/tests/map_unittest.cc
index 9a15253..499a67b 100644
--- a/mojo/public/cpp/bindings/tests/map_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/map_unittest.cc
@@ -246,7 +246,8 @@
     Array_Data<Map_Data<int32_t, int8_t>*>* data;
     ArrayValidateParams validate_params(
         0, false, new ArrayValidateParams(0, false, nullptr));
-    SerializeArray_(&array, &buf, &data, &validate_params);
+    EXPECT_EQ(internal::VALIDATION_ERROR_NONE,
+              SerializeArray_(&array, &buf, &data, &validate_params));
 
     Array<Map<int32_t, int8_t>> deserialized_array;
     Deserialize_(data, &deserialized_array);
@@ -269,7 +270,8 @@
     ArrayValidateParams validate_params(
         0, false, new ArrayValidateParams(
                       0, false, new ArrayValidateParams(0, false, nullptr)));
-    SerializeArray_(&array, &buf, &data, &validate_params);
+    EXPECT_EQ(internal::VALIDATION_ERROR_NONE,
+              SerializeArray_(&array, &buf, &data, &validate_params));
 
     Array<Map<String, Array<bool>>> deserialized_array;
     Deserialize_(data, &deserialized_array);
diff --git a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc
index b61d3bc..85b0924 100644
--- a/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/serialization_warning_unittest.cc
@@ -57,29 +57,21 @@
   template <typename T, typename TPtr>
   void TestStructWarningImpl(TPtr obj,
                              mojo::internal::ValidationError expected_warning) {
-    warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE);
-
     mojo::internal::FixedBufferForTesting buf(GetSerializedSize_(*obj));
     typename T::Data_* data;
-    Serialize_(obj.get(), &buf, &data);
-
-    EXPECT_EQ(expected_warning, warning_observer_.last_warning());
+    EXPECT_EQ(expected_warning, Serialize_(obj.get(), &buf, &data));
   }
 
   template <typename T>
   void TestArrayWarning(T obj,
                         mojo::internal::ValidationError expected_warning,
                         const ArrayValidateParams* validate_params) {
-    warning_observer_.set_last_warning(mojo::internal::VALIDATION_ERROR_NONE);
-
     mojo::internal::FixedBufferForTesting buf(GetSerializedSize_(obj));
     typename T::Data_* data;
-    SerializeArray_(&obj, &buf, &data, validate_params);
-
-    EXPECT_EQ(expected_warning, warning_observer_.last_warning());
+    EXPECT_EQ(expected_warning,
+              SerializeArray_(&obj, &buf, &data, validate_params));
   }
 
-  mojo::internal::SerializationWarningObserverForTesting warning_observer_;
   Environment env_;
 };
 
diff --git a/mojo/public/cpp/bindings/tests/struct_unittest.cc b/mojo/public/cpp/bindings/tests/struct_unittest.cc
index 283dd8e..8a3dadf 100644
--- a/mojo/public/cpp/bindings/tests/struct_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/struct_unittest.cc
@@ -5,6 +5,7 @@
 #include <string.h>
 
 #include "mojo/public/cpp/bindings/lib/fixed_buffer.h"
+#include "mojo/public/cpp/bindings/lib/validation_errors.h"
 #include "mojo/public/cpp/environment/environment.h"
 #include "mojo/public/cpp/system/message_pipe.h"
 #include "mojo/public/interfaces/bindings/tests/test_structs.mojom.h"
@@ -54,7 +55,8 @@
   size_t size = GetSerializedSize_(*input);
   mojo::internal::FixedBufferForTesting buf(size + 32);
   InputDataType data;
-  Serialize_(input.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(input.get(), &buf, &data));
 
   std::vector<Handle> handles;
   data->EncodePointersAndHandles(&handles);
@@ -144,7 +146,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::Rect_Data* data;
-  Serialize_(rect.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(rect.get(), &buf, &data));
 
   RectPtr rect2(Rect::New());
   Deserialize_(data, rect2.get());
@@ -177,7 +180,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::RectPair_Data* data;
-  Serialize_(pair.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(pair.get(), &buf, &data));
 
   RectPairPtr pair2(RectPair::New());
   Deserialize_(data, pair2.get());
@@ -208,7 +212,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::NamedRegion_Data* data;
-  Serialize_(region.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(region.get(), &buf, &data));
 
   NamedRegionPtr region2(NamedRegion::New());
   Deserialize_(data, region2.get());
@@ -234,7 +239,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::NamedRegion_Data* data;
-  Serialize_(region.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(region.get(), &buf, &data));
 
   NamedRegionPtr region2(NamedRegion::New());
   Deserialize_(data, region2.get());
diff --git a/mojo/public/cpp/bindings/tests/union_unittest.cc b/mojo/public/cpp/bindings/tests/union_unittest.cc
index 4df0f21..afeb4a5 100644
--- a/mojo/public/cpp/bindings/tests/union_unittest.cc
+++ b/mojo/public/cpp/bindings/tests/union_unittest.cc
@@ -501,7 +501,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::SmallStruct_Data* data = nullptr;
-  Serialize_(small_struct.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(small_struct.get(), &buf, &data));
 
   SmallStructPtr deserialized(SmallStruct::New());
   Deserialize_(data, deserialized.get());
@@ -521,7 +522,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::SmallObjStruct_Data* data = nullptr;
-  Serialize_(obj_struct.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(obj_struct.get(), &buf, &data));
 
   std::vector<Handle> handles;
   data->EncodePointersAndHandles(&handles);
@@ -544,7 +546,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::SmallStruct_Data* data = nullptr;
-  Serialize_(small_struct.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(small_struct.get(), &buf, &data));
 
   std::vector<Handle> handles;
   data->EncodePointersAndHandles(&handles);
@@ -568,7 +571,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::SmallStruct_Data* data = nullptr;
-  Serialize_(small_struct.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(small_struct.get(), &buf, &data));
   data->pod_union.tag = static_cast<internal::PodUnion_Data::PodUnion_Tag>(100);
 
   std::vector<Handle> handles;
@@ -611,7 +615,8 @@
 
   mojo::internal::FixedBufferForTesting buf(size);
   internal::SmallStruct_Data* data = nullptr;
-  Serialize_(small_struct.get(), &buf, &data);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            Serialize_(small_struct.get(), &buf, &data));
 
   std::vector<Handle> handles;
   data->EncodePointersAndHandles(&handles);
@@ -655,7 +660,8 @@
   mojo::internal::Map_Data<mojo::internal::String_Data*,
                            internal::PodUnion_Data>* data;
   mojo::internal::ArrayValidateParams validate_params(0, false, nullptr);
-  SerializeMap_(&map, &buf, &data, &validate_params);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            SerializeMap_(&map, &buf, &data, &validate_params));
 
   Map<String, PodUnionPtr> map2;
   Deserialize_(data, &map2);
@@ -679,7 +685,8 @@
   mojo::internal::Map_Data<mojo::internal::String_Data*,
                            internal::PodUnion_Data>* data;
   mojo::internal::ArrayValidateParams validate_params(0, true, nullptr);
-  SerializeMap_(&map, &buf, &data, &validate_params);
+  EXPECT_EQ(mojo::internal::VALIDATION_ERROR_NONE,
+            SerializeMap_(&map, &buf, &data, &validate_params));
 
   Map<String, PodUnionPtr> map2;
   Deserialize_(data, &map2);
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
index e428704..a8fcdba 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/interface_definition.tmpl
@@ -26,7 +26,7 @@
 {%- endmacro %}
 
 {%- macro build_message(struct, struct_display_name) -%}
-  {{struct_macros.serialize(struct, struct_display_name, "in_%s", "params", "builder.buffer()")}}
+  {{struct_macros.serialize(struct, struct_display_name, "in_%s", "params", "builder.buffer()", false)}}
   params->EncodePointersAndHandles(builder.message()->mutable_handles());
 {%- endmacro %}
 
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
index b38bd45..cde243f 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_macros.tmpl
@@ -26,6 +26,88 @@
 {%-   endfor %}
 {%- endmacro -%}
 
+{# A private macro that prints the C++ log-and-report serialization errors
+   macro, and conditionally returns if |should_return_errors| #}
+{%- macro _validation_check_macro(condition, error_code, error_msg, should_return_errors=false) -%}
+  if ({{condition}}) {
+    MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING({{error_code}}, "{{error_msg}}");
+  {%- if should_return_errors %}
+    return {{error_code}};
+  {%- endif %}
+  }
+{%- endmacro -%}
+
+{# The following 4 macros call |SerializeArray_|, |SerializeMap_|,
+   |SerializeUnion_| and |Serialize_| respectively.  If |should_return_error|
+   is true, these macros do the extra work of propagating non-successful error
+   codes. #} 
+{%- macro call_serialize_array(name, kind, input, buffer, output,
+                               should_return_errors, indent_size) -%}
+  {
+    const mojo::internal::ArrayValidateParams {{name}}_validate_params(
+      {{kind|get_array_validate_params_ctor_args|indent(indent_size)}});
+{%-       if should_return_errors -%}
+    auto retval =
+{%-       endif -%}
+    mojo::SerializeArray_({{input}}, {{buffer}}, {{output}},
+                          &{{name}}_validate_params);
+{%-       if should_return_errors %}
+    if (retval != mojo::internal::VALIDATION_ERROR_NONE)
+      return retval;
+{%-       endif %}
+  }
+{%- endmacro -%}
+
+{%- macro call_serialize_map(name, kind, input, buffer, output,
+                             should_return_errors, indent_size) -%}
+  {
+    const mojo::internal::ArrayValidateParams {{name}}_validate_params(
+        {{kind.value_kind|get_map_validate_params_ctor_args|indent(indent_size)}});
+{%- if should_return_errors -%}
+    auto retval =
+{%- endif -%}
+    mojo::SerializeMap_(
+        {{input}}, {{buffer}}, {{output}},
+        &{{name}}_validate_params);
+{%- if should_return_errors %}
+    if (retval != mojo::internal::VALIDATION_ERROR_NONE)
+      return retval;
+{%- endif %}
+  }
+{%- endmacro -%}
+
+{%- macro call_serialize_union(input, buffer, output, inlined,
+                               should_return_errors) -%}  
+  {
+{%- if should_return_errors -%}
+    auto retval =
+{%- endif -%}
+    SerializeUnion_({{input}},
+                    {{buffer}},
+                    {{output}},
+                    {{inlined}});
+{%- if should_return_errors %}
+    if (retval != mojo::internal::VALIDATION_ERROR_NONE)
+      return retval;
+{%- endif %}
+  }
+{%- endmacro -%}
+
+{%- macro call_serialize_struct(input, buffer, output, should_return_errors) -%}  
+  {
+{%- if should_return_errors -%}
+    auto retval =
+{%- endif -%}
+    Serialize_({{input}},
+               {{buffer}},
+               {{output}});
+{%- if should_return_errors %}
+    if (retval != mojo::internal::VALIDATION_ERROR_NONE)
+      return retval;
+{%- endif %}
+  }
+{%- endmacro -%}
+
 {#  Serializes the specified struct.
     |struct| is the struct definition.
     |struct_display_name| is the display name for the struct that can be showed
@@ -35,12 +117,18 @@
     substituted with struct field names to refer to the input fields.
     |output| is the name of the output struct instance.
     |buffer| is the name of the Buffer instance used.
+    |should_return_errors| is true if validation errors need to be return'd. 
+    This is needed when serializing interface parameters, where you cannot
+    return.
+
     This macro is expanded to do serialization for both:
     - user-defined structs: the input is an instance of the corresponding struct
       wrapper class.
     - method parameters/response parameters: the input is a list of
-      arguments. #}
-{%- macro serialize(struct, struct_display_name, input_field_pattern, output, buffer) -%}
+      arguments.
+    This macro is expanded within the C++ struct serialization methods #}
+{%- macro serialize(struct, struct_display_name, input_field_pattern,
+                    output, buffer, should_return_errors=false) -%}
   internal::{{struct.name}}_Data* {{output}} =
       internal::{{struct.name}}_Data::New({{buffer}});
 {%- for pf in struct.packed.packed_fields_in_ordinal_order %}
@@ -49,33 +137,47 @@
 {%-   set kind = pf.field.kind %}
 {%-   if kind|is_object_kind %}
 {%-     if kind|is_array_kind %}
-  const mojo::internal::ArrayValidateParams {{name}}_validate_params(
-      {{kind|get_array_validate_params_ctor_args|indent(10)}});
-  mojo::SerializeArray_(&{{input_field}}, {{buffer}},
-      &{{output}}->{{name}}.ptr, &{{name}}_validate_params);
+  {{call_serialize_array(name = name,
+                         kind = kind,
+                         input = '&' ~ input_field,
+                         buffer = buffer,
+                         output = "&%s->%s.ptr"|format(output,name),
+                         should_return_errors = should_return_errors,
+                         indent_size = 10)}}
 {%-     elif kind|is_map_kind %}
-  const mojo::internal::ArrayValidateParams {{name}}_validate_params(
-      {{kind.value_kind|get_map_validate_params_ctor_args|indent(10)}});
-  mojo::SerializeMap_(
-      &{{input_field}}, {{buffer}}, &{{output}}->{{name}}.ptr,
-      &{{name}}_validate_params);
+  {{call_serialize_map(name = name,
+                       kind = kind,
+                       input = '&' ~ input_field,
+                       buffer = buffer,
+                       output = '&%s->%s.ptr'|format(output,name),
+                       should_return_errors = should_return_errors,
+                       indent_size = 10)}}
 {%-     elif kind|is_union_kind %}
   internal::{{kind.name}}_Data* {{name}}_ptr = &{{output}}->{{name}};
-  SerializeUnion_({{input_field}}.get(), {{buffer}}, &{{name}}_ptr, true);
+  {{call_serialize_union(input = input_field ~ ".get()",
+                         buffer = buffer,
+                         output = "&%s_ptr"|format(name),
+                         inlined = "true",
+                         should_return_errors = should_return_errors)}}
 {%-     elif kind|is_string_kind %}
   SerializeString_({{input_field}}, {{buffer}}, &{{output}}->{{name}}.ptr);
 {%-     else %}
-  Serialize_({{input_field}}.get(), {{buffer}}, &{{output}}->{{name}}.ptr);
+  {{call_serialize_struct(input = input_field ~ ".get()",
+                          buffer = buffer,
+                          output = "&%s->%s.ptr"|format(output,name),
+                          should_return_errors = should_return_errors)}}
 {%-     endif %}
 {%-     if not kind|is_nullable_kind %}
-  MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
 {%-       if kind|is_union_kind %}
-      {{output}}->{{name}}.is_null(),
+{%-         set condition = "%s->%s.is_null()" | format(output, name) %}
 {%-       else %}
-      !{{output}}->{{name}}.ptr,
+{%-         set condition = "!%s->%s.ptr" | format(output,name) %}
 {%-       endif %}
-      mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER,
-      "null {{name}} in {{struct_display_name}}");
+  {{_validation_check_macro(
+    condition = condition,
+    error_code = "mojo::internal::VALIDATION_ERROR_UNEXPECTED_NULL_POINTER",
+    error_msg = "null %s in %s" | format(name, struct_display_name),
+    should_return_errors = should_return_errors)}}
 {%-     endif %}
 {%-   elif kind|is_any_handle_kind or kind|is_interface_kind %}
 {%-     if kind|is_interface_kind %}
@@ -86,14 +188,16 @@
   {{output}}->{{name}} = {{input_field}}.release();
 {%-     endif %}
 {%-     if not kind|is_nullable_kind %}
-  MOJO_INTERNAL_DLOG_SERIALIZATION_WARNING(
 {%-       if kind|is_interface_kind %}
-      !{{output}}->{{name}}.handle.is_valid(),
+{%-         set condition = "!%s->%s.handle.is_valid()" | format(output, name) %}
 {%-       else %}
-      !{{output}}->{{name}}.is_valid(),
+{%-         set condition = "!%s->%s.is_valid()" | format(output,name) %}
 {%-       endif %}
-      mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE,
-      "invalid {{name}} in {{struct_display_name}}");
+  {{_validation_check_macro(
+    condition = condition,
+    error_code = "mojo::internal::VALIDATION_ERROR_UNEXPECTED_INVALID_HANDLE",
+    error_msg = "invalid %s in %s" | format(name, struct_display_name),
+    should_return_errors = should_return_errors)}}
 {%-     endif %}
 {%-   elif kind|is_enum_kind %}
   {{output}}->{{name}} =
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
index 6243372..84534fd 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_declaration.tmpl
@@ -1,5 +1,7 @@
 size_t GetSerializedSize_(const {{struct.name}}& input);
-void Serialize_({{struct.name}}* input, mojo::internal::Buffer* buffer,
-                internal::{{struct.name}}_Data** output);
+mojo::internal::ValidationError Serialize_(
+    {{struct.name}}* input,
+    mojo::internal::Buffer* buffer,
+    internal::{{struct.name}}_Data** output);
 void Deserialize_(internal::{{struct.name}}_Data* input,
                   {{struct.name}}* output);
\ No newline at end of file
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl
index eb6fcec..752795b 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/struct_serialization_definition.tmpl
@@ -4,14 +4,17 @@
   return size;
 }
 
-void Serialize_({{struct.name}}* input, mojo::internal::Buffer* buf,
-                internal::{{struct.name}}_Data** output) {
+mojo::internal::ValidationError Serialize_(
+    {{struct.name}}* input,
+    mojo::internal::Buffer* buf,
+    internal::{{struct.name}}_Data** output) {
   if (input) {
-    {{struct_macros.serialize(struct, struct.name ~ " struct", "input->%s", "result", "buf")|indent(2)}}
+    {{struct_macros.serialize(struct, struct.name ~ " struct", "input->%s", "result", "buf", true)|indent(2)}}
     *output = result;
   } else {
     *output = nullptr;
   }
+  return mojo::internal::VALIDATION_ERROR_NONE;
 }
 
 void Deserialize_(internal::{{struct.name}}_Data* input,
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
index 588e749..d29a356 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_declaration.tmpl
@@ -1,5 +1,7 @@
 size_t GetSerializedSize_(const {{union.name}}Ptr& input, bool inlined);
-void SerializeUnion_({{union.name}}* input, mojo::internal::Buffer* buffer,
-                         internal::{{union.name}}_Data** output, bool inlined);
+mojo::internal::ValidationError SerializeUnion_(
+    {{union.name}}* input,
+    mojo::internal::Buffer* buffer,
+    internal::{{union.name}}_Data** output, bool inlined);
 void Deserialize_(internal::{{union.name}}_Data* input,
                   {{union.name}}* output);
\ No newline at end of file
diff --git a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
index 4acbeb2..c0fa566 100644
--- a/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
+++ b/mojo/public/tools/bindings/generators/cpp_templates/union_serialization_definition.tmpl
@@ -1,3 +1,4 @@
+{% import 'struct_macros.tmpl' as struct_macros without context %} 
 size_t GetSerializedSize_(const {{union.name}}Ptr& input, bool inlined) {
   size_t size = 0U;
   if (!inlined) {
@@ -28,8 +29,11 @@
   return size;
 }
 
-void SerializeUnion_({{union.name}}* input, mojo::internal::Buffer* buf,
-                     internal::{{union.name}}_Data** output, bool inlined) {
+mojo::internal::ValidationError SerializeUnion_(
+    {{union.name}}* input,
+    mojo::internal::Buffer* buf,
+    internal::{{union.name}}_Data** output,
+    bool inlined) {
   internal::{{union.name}}_Data* result = *output;
   if (input) {
     if (!inlined) {
@@ -49,25 +53,36 @@
             *input_acc.data()->{{field.name}},
             buf, &result->data.f_{{field.name}}.ptr);
 {%      elif field.kind|is_struct_kind %}
-        Serialize_(
-            input_acc.data()->{{field.name}}->get(),
-            buf, &result->data.f_{{field.name}}.ptr);
+          {{struct_macros.call_serialize_struct(
+              input = "input_acc.data()->%s->get()"|format(field.name),
+              buffer = "buf",
+              output = "&result->data.f_%s.ptr"|format(field.name),
+              should_return_errors = true)|indent(6)}}
 {%      elif field.kind|is_union_kind %}
-        SerializeUnion_(
-            input_acc.data()->{{field.name}}->get(),
-            buf, &result->data.f_{{field.name}}.ptr, false);
+          {{struct_macros.call_serialize_union(
+              input = "input_acc.data()->%s->get()"|format(field.name),
+              buffer = "buf",
+              output = "&result->data.f_%s.ptr"|format(field.name),
+              inlined = "false",
+              should_return_errors = true)|indent(6)}}
 {%      elif field.kind|is_array_kind %}
-        const mojo::internal::ArrayValidateParams {{field.name}}_validate_params(
-            {{field.kind|get_array_validate_params_ctor_args|indent(16)}});
-        SerializeArray_(
-            input_acc.data()->{{field.name}},
-            buf, &result->data.f_{{field.name}}.ptr, &{{field.name}}_validate_params);
+          {{struct_macros.call_serialize_array(
+              name = field.name,
+              kind = field.kind,
+              input = "input_acc.data()->%s"|format(field.name),
+              buffer = "buf",
+              output = "&result->data.f_%s.ptr"|format(field.name),
+              should_return_errors = true,
+              indent_size = 16)|indent(6)}}
 {%      elif field.kind|is_map_kind %}
-        const mojo::internal::ArrayValidateParams {{field.name}}_validate_params(
-            {{field.kind.value_kind|get_map_validate_params_ctor_args|indent(16)}});
-        SerializeMap_(
-            input_acc.data()->{{field.name}},
-            buf, &result->data.f_{{field.name}}.ptr, &{{field.name}}_validate_params);
+          {{struct_macros.call_serialize_map(
+              name = field.name,
+              kind = field.kind,
+              input = "input_acc.data()->%s"|format(field.name),
+              buffer = "buf",
+              output = "&result->data.f_%s.ptr"|format(field.name),
+              should_return_errors = true,
+              indent_size = 16)|indent(6)}}
 {%-     endif %}
 {%    elif field.kind|is_any_handle_kind %}
         result->data.f_{{field.name}} =
@@ -88,6 +103,7 @@
       }
 {%- endfor %}
       default:
+        // TODO(vardhan): Should this return an error code instead?
         MOJO_CHECK(false) << "No sane way to serialize a union with an unknown tag.";
         break;
     }
@@ -97,6 +113,7 @@
     result = nullptr;
   }
   *output = result;
+  return mojo::internal::VALIDATION_ERROR_NONE;
 }
 
 void Deserialize_(internal::{{union.name}}_Data* input,