Weave Data Management mobile support improvements

-- Add onFlushUpdateComplete callback to notify failed path results to
application, for each flushed path, if systemError is WEAVE_ERROR_STATUS_REPORT_RECEIVED,
application would receive the device Error Exception including status
report, particular path and dataSink object, otherwise, application would receive the
local error exception, particular path and dataSink object. Add objective C, Java, and Python implementation for the above exceptions.
-- Add DeleteData API so that application can delete data in particular
path.
-- Add length check for GetString and GetStringArray.
-- When GetTraitSchemaEngine fails, it means user does not load the
correct profile id, update err with WEAVE_ERROR_INVALID_PROFILE_ID
-- When refresh fails, we use onError to pass the status report and
error.
-- Fix some style issues.
-- Update onFlushUpdateComplete and DeleteData APIs for objective C, Java, Python
-- Clean redundant code in NLGenericTraitUpdatableDataSink
-- Adjust the signature for getString, getBytes, and getStringArray, and
pass val as reference, and return error code for objectice C support.
-- Fix TLV Dump for empty string.
diff --git a/src/device-manager/WeaveDataManagementClient.cpp b/src/device-manager/WeaveDataManagementClient.cpp
index 094efc6..ec2cc47 100644
--- a/src/device-manager/WeaveDataManagementClient.cpp
+++ b/src/device-manager/WeaveDataManagementClient.cpp
@@ -498,7 +498,6 @@
     nl::Weave::TLV::TLVReader reader;
     PacketBuffer * pMsgBuf                = NULL;
     PropertyPathHandle propertyPathHandle = kNullPropertyPathHandle;
-    ;
     std::map<PropertyPathHandle, PacketBuffer *>::iterator it;
 
     err = GetSchemaEngine()->MapPathToHandle(apPath, propertyPathHandle);
@@ -537,7 +536,6 @@
     nl::Weave::TLV::TLVReader reader;
     PacketBuffer * pMsgBuf                = NULL;
     PropertyPathHandle propertyPathHandle = kNullPropertyPathHandle;
-    ;
     std::map<PropertyPathHandle, PacketBuffer *>::iterator it;
 
     err = GetSchemaEngine()->MapPathToHandle(apPath, propertyPathHandle);
@@ -558,8 +556,12 @@
     SuccessOrExit(err);
 
     apBytesData->mDataLen = reader.GetLength();
-    err                   = reader.GetDataPtr(apBytesData->mpDataBuf);
-    SuccessOrExit(err);
+    WeaveLogProgress(DataManagement, "GetBytes with length %d", apBytesData->mDataLen);
+    if (apBytesData->mDataLen != 0)
+    {
+        err = reader.GetDataPtr(apBytesData->mpDataBuf);
+        SuccessOrExit(err);
+    }
 
 exit:
     WeaveLogFunctError(err);
@@ -618,7 +620,6 @@
     nl::Weave::TLV::TLVReader reader;
     PacketBuffer * pMsgBuf                = NULL;
     PropertyPathHandle propertyPathHandle = kNullPropertyPathHandle;
-    ;
     std::map<PropertyPathHandle, PacketBuffer *>::iterator it;
 
     err = GetSchemaEngine()->MapPathToHandle(apPath, propertyPathHandle);
@@ -658,7 +659,6 @@
     nl::Weave::TLV::TLVReader reader;
     PacketBuffer * pMsgBuf                = NULL;
     PropertyPathHandle propertyPathHandle = kNullPropertyPathHandle;
-    ;
     TLVType OuterContainerType;
     std::map<PropertyPathHandle, PacketBuffer *>::iterator it;
 
@@ -686,8 +686,13 @@
     {
         int length               = reader.GetLength();
         const uint8_t * pDataBuf = NULL;
-        err                      = reader.GetDataPtr(pDataBuf);
-        SuccessOrExit(err);
+        WeaveLogProgress(DataManagement, "GetStringArray with length %d", length);
+        if (length != 0)
+        {
+            err = reader.GetDataPtr(pDataBuf);
+            SuccessOrExit(err);
+        }
+
         std::string val((char *) pDataBuf, length);
         aValueVector.push_back(val);
     }
@@ -740,6 +745,36 @@
     return err;
 }
 
+WEAVE_ERROR GenericTraitUpdatableDataSink::DeleteData(const char * apPath)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    nl::Weave::TLV::TLVReader reader;
+    PacketBuffer * pMsgBuf                = NULL;
+    PropertyPathHandle propertyPathHandle = kNullPropertyPathHandle;
+    std::map<PropertyPathHandle, PacketBuffer *>::iterator it;
+
+    err = GetSchemaEngine()->MapPathToHandle(apPath, propertyPathHandle);
+    SuccessOrExit(err);
+
+    it = mPathTlvDataMap.find(propertyPathHandle);
+    VerifyOrExit(it != mPathTlvDataMap.end(), err = WEAVE_ERROR_INVALID_TLV_TAG);
+
+    if (NULL != it->second)
+    {
+        PacketBuffer::Free(it->second);
+        it->second = NULL;
+        WeaveLogProgress(DataManagement, "Deleted data in mPathTlvDataMap for path %s", apPath);
+    }
+
+    mPathTlvDataMap.erase(it);
+
+    err = ClearUpdated(GetSubscriptionClient(), propertyPathHandle);
+
+exit:
+    WeaveLogFunctError(err);
+    return err;
+}
+
 WEAVE_ERROR
 GenericTraitUpdatableDataSink::SetLeafData(PropertyPathHandle aLeafHandle, TLVReader & aReader)
 {
@@ -903,9 +938,9 @@
 {
     WEAVE_ERROR err              = WEAVE_NO_ERROR;
     WdmClient * const pWdmClient = reinterpret_cast<WdmClient *>(aAppState);
-
-    OpState savedOpState = pWdmClient->mOpState;
-    WeaveLogDetail(DataManagement, "WDM ClientEventCallback: current op is, %d", savedOpState);
+    DeviceStatus * deviceStatus  = NULL;
+    OpState savedOpState         = pWdmClient->mOpState;
+    WeaveLogDetail(DataManagement, "WdmClient ClientEventCallback: current op is, %d, event is %d", savedOpState, aEvent);
 
     switch (aEvent)
     {
@@ -984,31 +1019,46 @@
     case SubscriptionClient::kEvent_OnSubscriptionTerminated:
         WeaveLogDetail(DataManagement, "Client->kEvent_OnSubscriptionTerminated. Reason: %u, peer = 0x%" PRIX64 "\n",
                        aInParam.mSubscriptionTerminated.mReason, aInParam.mSubscriptionTerminated.mClient->GetPeerNodeId());
-        pWdmClient->mpSubscriptionClient->AbortSubscription();
-        err = WEAVE_ERROR_INCORRECT_STATE;
+        VerifyOrExit(kOpState_RefreshData == savedOpState, err = WEAVE_ERROR_INCORRECT_STATE);
+        deviceStatus                  = new DeviceStatus();
+        deviceStatus->StatusProfileId = aInParam.mSubscriptionTerminated.mStatusProfileId;
+        deviceStatus->StatusCode      = aInParam.mSubscriptionTerminated.mStatusCode;
+        deviceStatus->SystemErrorCode = aInParam.mSubscriptionTerminated.mReason;
+        err                           = aInParam.mSubscriptionTerminated.mReason;
         break;
     case SubscriptionClient::kEvent_OnUpdateComplete:
+        VerifyOrExit(kOpState_FlushUpdate == savedOpState, err = WEAVE_ERROR_INCORRECT_STATE);
         if ((aInParam.mUpdateComplete.mReason == WEAVE_NO_ERROR) &&
             (nl::Weave::Profiles::kWeaveProfile_Common == aInParam.mUpdateComplete.mStatusProfileId) &&
             (nl::Weave::Profiles::Common::kStatus_Success == aInParam.mUpdateComplete.mStatusCode))
         {
-            WeaveLogDetail(DataManagement, "Update: path result: success");
+            WeaveLogDetail(DataManagement, "Update: path result: success, tdh %" PRIu16 ", ph %" PRIu16 ".",
+                           aInParam.mUpdateComplete.mTraitDataHandle, aInParam.mUpdateComplete.mPropertyPathHandle);
         }
         else
         {
-            WeaveLogDetail(DataManagement, "Update: path failed: %s, %s, tdh %" PRIu16 ", will %sretry, discard failed change",
+
+            WeaveLogDetail(DataManagement,
+                           "Update: path failed: %s, %s, tdh %" PRIu16 ", ph %" PRIu16 ", %s, discard failed change",
                            ErrorStr(aInParam.mUpdateComplete.mReason),
                            nl::StatusReportStr(aInParam.mUpdateComplete.mStatusProfileId, aInParam.mUpdateComplete.mStatusCode),
-                           aInParam.mUpdateComplete.mTraitDataHandle, aInParam.mUpdateComplete.mWillRetry ? "" : "not ");
+                           aInParam.mUpdateComplete.mTraitDataHandle, aInParam.mUpdateComplete.mPropertyPathHandle,
+                           aInParam.mUpdateComplete.mWillRetry ? "will retry" : "will not retry");
+
+            err = pWdmClient->UpdateFailedPathResults(
+                pWdmClient, aInParam.mUpdateComplete.mTraitDataHandle, aInParam.mUpdateComplete.mPropertyPathHandle,
+                aInParam.mUpdateComplete.mReason, aInParam.mUpdateComplete.mStatusProfileId, aInParam.mUpdateComplete.mStatusCode);
         }
 
         break;
     case SubscriptionClient::kEvent_OnNoMorePendingUpdates:
-        // TODO: notify application with all status for updated paths
         WeaveLogDetail(DataManagement, "Update: no more pending updates");
         VerifyOrExit(kOpState_FlushUpdate == savedOpState, err = WEAVE_ERROR_INCORRECT_STATE);
         pWdmClient->mpSubscriptionClient->DiscardUpdates();
-        pWdmClient->mOnComplete.General(pWdmClient->mpContext, pWdmClient->mpAppReqState);
+        pWdmClient->mOnComplete.FlushUpdate(pWdmClient->mpContext, pWdmClient->mpAppReqState,
+                                            pWdmClient->mFailedFlushPathStatus.size(), pWdmClient->mFailedFlushPathStatus.data());
+        pWdmClient->mFailedFlushPathStatus.clear();
+        pWdmClient->mFailedPaths.clear();
         pWdmClient->mpContext = NULL;
         pWdmClient->ClearOpState();
         break;
@@ -1021,12 +1071,37 @@
 exit:
     if (WEAVE_NO_ERROR != err)
     {
-        WeaveLogError(DataManagement, "WDM ClientEventCallback failure: err = %d", err);
-        pWdmClient->mOnError(pWdmClient->mpContext, pWdmClient->mpAppReqState, err, NULL);
+        WeaveLogError(DataManagement, "WdmClient ClientEventCallback failure: err = %d", err);
+
+        if (pWdmClient->mOnError)
+        {
+            pWdmClient->mOnError(pWdmClient->mpContext, pWdmClient->mpAppReqState, err, deviceStatus);
+            pWdmClient->mOnError = NULL;
+        }
+
+        if (kOpState_FlushUpdate == savedOpState)
+        {
+            pWdmClient->mpSubscriptionClient->DiscardUpdates();
+            pWdmClient->mFailedFlushPathStatus.clear();
+            pWdmClient->mFailedPaths.clear();
+        }
+
+        if (kOpState_RefreshData == savedOpState)
+        {
+            pWdmClient->mpSubscriptionClient->AbortSubscription();
+            pWdmClient->mSinkCatalog.Iterate(ClearDataSinkVersion, pWdmClient);
+        }
+
         pWdmClient->mpContext = NULL;
         pWdmClient->ClearOpState();
     }
 
+    if (deviceStatus != NULL)
+    {
+        delete deviceStatus;
+        deviceStatus = NULL;
+    }
+
     return;
 }
 
@@ -1050,6 +1125,8 @@
     State     = kState_Initialized;
     mpContext = NULL;
     ClearOpState();
+    mFailedFlushPathStatus.clear();
+    mFailedPaths.clear();
 
 exit:
     return WEAVE_NO_ERROR;
@@ -1060,6 +1137,40 @@
     mSinkCatalog.SetNodeId(aNodeId);
 }
 
+WEAVE_ERROR WdmClient::UpdateFailedPathResults(WdmClient * const apWdmClient, TraitDataHandle mTraitDataHandle,
+                                               PropertyPathHandle mPropertyPathHandle, uint32_t aReason, uint32_t aStatusProfileId,
+                                               uint16_t aStatusCode)
+{
+    TraitDataSink * dataSink = NULL;
+    WEAVE_ERROR err          = WEAVE_NO_ERROR;
+    WdmClientFlushUpdateStatus updateStatus;
+    std::string path;
+
+    err = apWdmClient->mSinkCatalog.Locate(mTraitDataHandle, &dataSink);
+    SuccessOrExit(err);
+
+    err = dataSink->GetSchemaEngine()->MapHandleToPath(mPropertyPathHandle, path);
+    SuccessOrExit(err);
+
+    mFailedPaths.push_back(path);
+    updateStatus.mpPath                     = mFailedPaths.back().c_str();
+    updateStatus.mPathLen                   = mFailedPaths.back().length();
+    updateStatus.mErrorCode                 = aReason;
+    updateStatus.mDevStatus.SystemErrorCode = aReason;
+    updateStatus.mDevStatus.StatusProfileId = aStatusProfileId;
+    updateStatus.mDevStatus.StatusCode      = aStatusCode;
+    updateStatus.mpDataSink                 = dataSink;
+    mFailedFlushPathStatus.push_back(updateStatus);
+    WeaveLogError(DataManagement, "Update: faild path is %s, length is %d", updateStatus.mpPath, updateStatus.mPathLen);
+
+exit:
+    if (WEAVE_NO_ERROR != err)
+    {
+        WeaveLogError(DataManagement, "Fail in UpdateFailedPathResults with err = %d", err);
+    }
+    return err;
+}
+
 WEAVE_ERROR WdmClient::NewDataSink(const ResourceIdentifier & aResourceId, uint32_t aProfileId, uint64_t aInstanceId,
                                    const char * apPath, GenericTraitUpdatableDataSink *& apGenericTraitUpdatableDataSink)
 {
@@ -1067,7 +1178,7 @@
     PropertyPathHandle handle = kNullPropertyPathHandle;
 
     const TraitSchemaEngine * pEngine = TraitSchemaDirectory::GetTraitSchemaEngine(aProfileId);
-    VerifyOrExit(pEngine != NULL, err = WEAVE_ERROR_INCORRECT_STATE);
+    VerifyOrExit(pEngine != NULL, err = WEAVE_ERROR_INVALID_PROFILE_ID);
 
     VerifyOrExit(mpSubscriptionClient != NULL, err = WEAVE_ERROR_INCORRECT_STATE);
 
@@ -1093,6 +1204,7 @@
     apGenericTraitUpdatableDataSink->SetSubscriptionClient(mpSubscriptionClient);
 
 exit:
+    WeaveLogFunctError(err);
     return err;
 }
 
@@ -1111,15 +1223,19 @@
     return err;
 }
 
-WEAVE_ERROR WdmClient::FlushUpdate(void * apAppReqState, DMCompleteFunct onComplete, DMErrorFunct onError)
+WEAVE_ERROR WdmClient::FlushUpdate(void * apAppReqState, DMFlushUpdateCompleteFunct onComplete, DMErrorFunct onError)
 {
     VerifyOrExit(mOpState == kOpState_Idle, WeaveLogError(DataManagement, "FlushUpdate with OpState %d", mOpState));
 
-    mpAppReqState       = apAppReqState;
-    mOnComplete.General = onComplete;
-    mOnError            = onError;
-    mOpState            = kOpState_FlushUpdate;
-    mpContext           = this;
+    mpAppReqState           = apAppReqState;
+    mOnComplete.FlushUpdate = onComplete;
+    mOnError                = onError;
+    mOpState                = kOpState_FlushUpdate;
+    mpContext               = this;
+
+    mFailedFlushPathStatus.clear();
+    mFailedPaths.clear();
+
     mpSubscriptionClient->FlushUpdate(true);
 
 exit:
diff --git a/src/device-manager/WeaveDataManagementClient.h b/src/device-manager/WeaveDataManagementClient.h
index 24a8ed7..04b31df 100644
--- a/src/device-manager/WeaveDataManagementClient.h
+++ b/src/device-manager/WeaveDataManagementClient.h
@@ -38,6 +38,7 @@
 #include <Weave/Profiles/data-management/Current/GenericTraitCatalogImpl.h>
 #include <map>
 #include <vector>
+#include "WeaveDeviceManager.h"
 
 namespace nl {
 namespace Weave {
@@ -69,11 +70,22 @@
 
 class GenericTraitUpdatableDataSink;
 class WdmClient;
-class DeviceStatus;
+
+class WdmClientFlushUpdateStatus
+{
+public:
+    uint32_t mErrorCode;
+    DeviceStatus mDevStatus;
+    const char * mpPath;
+    uint32_t mPathLen;
+    TraitDataSink * mpDataSink;
+};
 
 extern "C" {
 typedef void (*DMCompleteFunct)(void * appState, void * appReqState);
 typedef void (*DMErrorFunct)(void * appState, void * appReqState, WEAVE_ERROR err, DeviceStatus * devStatus);
+typedef void (*DMFlushUpdateCompleteFunct)(void * appState, void * appReqState, uint16_t pathCount,
+                                           WdmClientFlushUpdateStatus * statusResults);
 typedef WEAVE_ERROR (*GetDataHandleFunct)(void * apContext, const TraitCatalogBase<TraitDataSink> * const apCatalog,
                                           TraitDataHandle & aHandle);
 };
@@ -83,6 +95,7 @@
     friend class WdmClient;
     using nl::Weave::Profiles::DataManagement_Current::TraitDataSink::SetData;
     using nl::Weave::Profiles::DataManagement_Current::TraitUpdatableDataSink::GetData;
+
 private:
     GenericTraitUpdatableDataSink(const nl::Weave::Profiles::DataManagement::TraitSchemaEngine * aEngine, WdmClient * apWdmClient);
     ~GenericTraitUpdatableDataSink(void);
@@ -114,6 +127,8 @@
     WEAVE_ERROR IsNull(const char * apPath, bool & aIsNull);
     WEAVE_ERROR GetStringArray(const char * apPath, std::vector<std::string> & aValueVector);
 
+    WEAVE_ERROR DeleteData(const char * apPath);
+
     void * mpAppState;
 
 private:
@@ -171,7 +186,7 @@
     WEAVE_ERROR NewDataSink(const ResourceIdentifier & aResourceId, uint32_t aProfileId, uint64_t aInstanceId, const char * apPath,
                             GenericTraitUpdatableDataSink *& apGenericTraitUpdatableDataSink);
 
-    WEAVE_ERROR FlushUpdate(void * apAppReqState, DMCompleteFunct onComplete, DMErrorFunct onError);
+    WEAVE_ERROR FlushUpdate(void * apAppReqState, DMFlushUpdateCompleteFunct onComplete, DMErrorFunct onError);
 
     WEAVE_ERROR RefreshData(void * apAppReqState, DMCompleteFunct onComplete, DMErrorFunct onError,
                             GetDataHandleFunct getDataHandleCb);
@@ -191,6 +206,7 @@
     union
     {
         DMCompleteFunct General;
+        DMFlushUpdateCompleteFunct FlushUpdate;
     } mOnComplete;
     DMErrorFunct mOnError;
     GetDataHandleFunct mGetDataHandle;
@@ -210,6 +226,10 @@
 
     WEAVE_ERROR UnsubscribePublisherTrait(TraitDataSink * apDataSink);
 
+    WEAVE_ERROR UpdateFailedPathResults(WdmClient * const apWdmClient, TraitDataHandle mTraitDataHandle,
+                                        PropertyPathHandle mPropertyPathHandle, uint32_t aReason, uint32_t aStatusProfileId,
+                                        uint16_t aStatusCode);
+
     GenericTraitSinkCatalog mSinkCatalog;
     TraitPath * mpPublisherPathList;
 
@@ -218,6 +238,8 @@
     void * mpContext;
     void * mpAppReqState;
     OpState mOpState;
+    std::vector<std::string> mFailedPaths;
+    std::vector<WdmClientFlushUpdateStatus> mFailedFlushPathStatus;
 };
 } // namespace DeviceManager
 } // namespace Weave
diff --git a/src/device-manager/cocoa/Makefile.am b/src/device-manager/cocoa/Makefile.am
index aecf906..64ebf32 100644
--- a/src/device-manager/cocoa/Makefile.am
+++ b/src/device-manager/cocoa/Makefile.am
@@ -66,6 +66,8 @@
     NLWdmClient.h                          \
     NLGenericTraitUpdatableDataSink.h      \
     NLResourceIdentifier.h                 \
+    NLWdmClientFlushUpdateError.h          \
+    NLWdmClientFlushUpdateDeviceStatusError.h       \
     $(NULL)
 
 noinst_HEADERS                           = \
@@ -75,8 +77,8 @@
     NLWeaveError_Protected.h               \
     NLWeaveDeviceManager_Protected.h       \
     NLWdmClient_Protected.h                \
-    NLGenericTraitUpdatableDataSink_Protected.h       \
     NLResourceIdentifier_Protected.h       \
+    NLGenericTraitUpdatableDataSink_Protected.h     \
     $(NULL)
 
 libNLWeaveDeviceManager_a_SOURCES        = \
@@ -102,6 +104,8 @@
     NLWdmClient.mm                         \
     NLGenericTraitUpdatableDataSink.mm     \
     NLResourceIdentifier.mm                \
+    NLWdmClientFlushUpdateError.mm         \
+    NLWdmClientFlushUpdateDeviceStatusError.mm                \
     $(NULL)
 
 endif # WEAVE_WITH_COCOA
diff --git a/src/device-manager/cocoa/NLGenericTraitUpdatableDataSink.h b/src/device-manager/cocoa/NLGenericTraitUpdatableDataSink.h
index 3b2bfd5..5618080 100644
--- a/src/device-manager/cocoa/NLGenericTraitUpdatableDataSink.h
+++ b/src/device-manager/cocoa/NLGenericTraitUpdatableDataSink.h
@@ -45,7 +45,7 @@
 - (NSString *)toErrorString:(WEAVE_ERROR)err;
 
 /**
- * clear trait data
+ * clear the whole trait data
  */
 - (void)clear;
 
@@ -229,12 +229,12 @@
 /**
  * Get the string value assigned to the property at the given path within this trait.
  */
-- (NSString *)getString:(NSString *)path;
+- (WEAVE_ERROR)getString:(NSString **)val path:(NSString *)path;
 
 /**
  * Get the bytes value assigned to the property at the given path within this trait.
  */
-- (NSData *)getBytes:(NSString *)path;
+- (WEAVE_ERROR)getBytes:(NSData **)val path:(NSString *)path;
 
 /**
  * Check if null property at the given path within this trait.
@@ -244,9 +244,11 @@
 /**
  * Get the string array value assigned to the property at the given path within this trait.
  */
-- (NSArray *)getStringArray:(NSString *)path;
+- (WEAVE_ERROR)getStringArray:(NSMutableArray **)val path:(NSString *)path;
 
 /** Returns the version of the trait represented by this data sink. */
 - (WEAVE_ERROR)getVersion:(uint64_t *)val;
 
+/** Delete the trait property data on particular path. */
+- (WEAVE_ERROR)deleteData:(NSString *)path;
 @end
diff --git a/src/device-manager/cocoa/NLGenericTraitUpdatableDataSink.mm b/src/device-manager/cocoa/NLGenericTraitUpdatableDataSink.mm
index fdf508b..5240570 100644
--- a/src/device-manager/cocoa/NLGenericTraitUpdatableDataSink.mm
+++ b/src/device-manager/cocoa/NLGenericTraitUpdatableDataSink.mm
@@ -128,18 +128,18 @@
     return result;
 }
 
-static void handleGenericUpdatableDataSinkComplete(void * dataSink, void * reqState)
+static void onGenericUpdatableDataSinkComplete(void * dataSink, void * reqState)
 {
-    WDM_LOG_DEBUG(@"handleGenericUpdatableDataSinkComplete");
+    WDM_LOG_DEBUG(@"onGenericUpdatableDataSinkComplete");
 
     NLGenericTraitUpdatableDataSink * sink = (__bridge NLGenericTraitUpdatableDataSink *) reqState;
     [sink DispatchAsyncCompletionBlock:nil];
 }
 
-static void handleGenericUpdatableDataSinkError(
+static void onGenericUpdatableDataSinkError(
     void * dataSink, void * appReqState, WEAVE_ERROR code, nl::Weave::DeviceManager::DeviceStatus * devStatus)
 {
-    WDM_LOG_DEBUG(@"handleGenericUpdatableDataSinkError");
+    WDM_LOG_DEBUG(@"onGenericUpdatableDataSinkError with error code %d\n", code);
 
     NSError * error = nil;
     NSDictionary * userInfo = nil;
@@ -336,7 +336,7 @@
             _mFailureHandler = [failureHandler copy];
 
             WEAVE_ERROR err = _mWeaveCppGenericTraitUpdatableDataSink->RefreshData(
-                (__bridge void *) self, handleGenericUpdatableDataSinkComplete, handleGenericUpdatableDataSinkError);
+                (__bridge void *) self, onGenericUpdatableDataSinkComplete, onGenericUpdatableDataSinkError);
 
             if (WEAVE_NO_ERROR != err) {
                 [self DispatchAsyncDefaultFailureBlockWithCode:err];
@@ -364,11 +364,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->SetData([path UTF8String], val, isConditionalBool);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from SetSigned, ignore");
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -390,12 +385,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->SetData([path UTF8String], val, isConditionalBool);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from SetUnsigned, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -417,11 +406,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->SetData([path UTF8String], val, isConditionalBool);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from SetDouble, ignore");
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -443,10 +427,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->SetBoolean([path UTF8String], valBool, isConditionalBool);
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from SetBoolean, ignore");
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -467,11 +447,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->SetString([path UTF8String], [val UTF8String], isConditionalBool);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from SetData, ignore");
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -493,11 +468,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->SetNull([path UTF8String], isConditionalBool);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from SetData, ignore");
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -521,11 +491,6 @@
             uint32_t valLen = (uint32_t)[val length];
             uint8_t * pVal = (uint8_t *) [val bytes];
             err = _mWeaveCppGenericTraitUpdatableDataSink->SetBytes([path UTF8String], pVal, valLen, isConditionalBool);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from SetBytes, ignore");
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -552,10 +517,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->SetStringArray([path UTF8String], stringVector, isConditionalBool);
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from SetStringArray, ignore");
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -620,13 +581,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->GetData([path UTF8String], result);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from GetSigned, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-                result = 0;
-            }
         });
     }
 
@@ -653,13 +607,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->GetData([path UTF8String], result);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from GetUnsigned, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-                result = 0;
-            }
         });
     }
 
@@ -686,13 +633,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->GetData([path UTF8String], result);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from GetDouble, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-                result = 0;
-            }
         });
     }
 
@@ -719,12 +659,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->GetBoolean([path UTF8String], result);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from GetBoolean, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -736,32 +670,29 @@
     return err;
 }
 
-- (NSString *)getString:(NSString *)path
+- (WEAVE_ERROR)getString:(NSString **)val path:(NSString *)path
 {
     __block WEAVE_ERROR err = WEAVE_NO_ERROR;
     __block nl::Weave::DeviceManager::BytesData bytesData;
-    NSString * result = nil;
+
     WDM_LOG_METHOD_SIG();
 
     VerifyOrExit(NULL != _mWeaveCppGenericTraitUpdatableDataSink, err = WEAVE_ERROR_INCORRECT_STATE);
 
     // need this bracket to use Verify macros
     {
-        // we use sync so the result is immediately available to the caller upon return
+        // we use sync so the bytesData is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->GetBytes([path UTF8String], &bytesData);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from GetString, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
-    result = [[NSString alloc] initWithBytes:bytesData.mpDataBuf length:bytesData.mDataLen encoding:NSUTF8StringEncoding];
 
 exit:
-    return result;
+    if ((WEAVE_NO_ERROR == err) && (NULL != val))
+    {
+        *val = [[NSString alloc] initWithBytes:bytesData.mpDataBuf length:bytesData.mDataLen encoding:NSUTF8StringEncoding];
+    }
+    return err;
 }
 
 - (WEAVE_ERROR)isNull:(BOOL *)val path:(NSString *)path;
@@ -779,12 +710,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->IsNull([path UTF8String], result);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from isNull, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
@@ -796,64 +721,59 @@
     return err;
 }
 
-- (NSData *)getBytes:(NSString *)path
+- (WEAVE_ERROR)getBytes:(NSData **)val path:(NSString *)path
 {
     __block WEAVE_ERROR err = WEAVE_NO_ERROR;
     __block nl::Weave::DeviceManager::BytesData bytesData;
-    NSData * result = nil;
     WDM_LOG_METHOD_SIG();
 
     VerifyOrExit(NULL != _mWeaveCppGenericTraitUpdatableDataSink, err = WEAVE_ERROR_INCORRECT_STATE);
+    VerifyOrExit(NULL != val, err = WEAVE_ERROR_INVALID_ARGUMENT);
 
     // need this bracket to use Verify macros
     {
-        // we use sync so the result is immediately available to the caller upon return
+        // we use sync so the bytesData is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->GetBytes([path UTF8String], &bytesData);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from GetBytes, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
-    result = [NSData dataWithBytes:bytesData.mpDataBuf length:bytesData.mDataLen];
 exit:
-    return result;
+    if ((WEAVE_NO_ERROR == err) && (NULL != val))
+    {
+        *val = [NSData dataWithBytes:bytesData.mpDataBuf length:bytesData.mDataLen];
+    }
+
+    return err;
 }
 
-- (NSArray *)getStringArray:(NSString *)path
+- (WEAVE_ERROR)getStringArray:(NSMutableArray **)val path:(NSString *)path
 {
     __block WEAVE_ERROR err = WEAVE_NO_ERROR;
     __block std::vector<std::string> stringVector;
-    NSMutableArray * arrayOut = [[NSMutableArray alloc] init];
 
     WDM_LOG_METHOD_SIG();
 
     VerifyOrExit(NULL != _mWeaveCppGenericTraitUpdatableDataSink, err = WEAVE_ERROR_INCORRECT_STATE);
+    VerifyOrExit(NULL != val, err = WEAVE_ERROR_INVALID_ARGUMENT);
 
     // need this bracket to use Verify macros
     {
-        // we use sync so the result is immediately available to the caller upon return
+        // we use sync so the stringVector is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             err = _mWeaveCppGenericTraitUpdatableDataSink->GetStringArray([path UTF8String], stringVector);
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from GetStringArray, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-            }
         });
     }
 
-    for (auto iter = stringVector.begin(); iter < stringVector.end(); iter++) {
-        [arrayOut addObject:[NSString stringWithCString:iter->c_str() encoding:[NSString defaultCStringEncoding]]];
-    }
-
 exit:
-    return arrayOut;
+    if ((WEAVE_NO_ERROR == err) && (NULL != val))
+    {
+        *val = [[NSMutableArray alloc] init];
+        for (auto iter = stringVector.begin(); iter < stringVector.end(); iter++) {
+            [*val addObject:[NSString stringWithCString:iter->c_str() encoding:[NSString defaultCStringEncoding]]];
+        }
+    }
+    return err;
 }
 
 - (WEAVE_ERROR)getVersion:(uint64_t *)val
@@ -871,13 +791,6 @@
         // we use sync so the result is immediately available to the caller upon return
         dispatch_sync(_mWeaveWorkQueue, ^() {
             result = _mWeaveCppGenericTraitUpdatableDataSink->GetVersion();
-
-            if (err == WEAVE_ERROR_INCORRECT_STATE) {
-                WDM_LOG_DEBUG(@"Got incorrect state error from GetVersion, ignore");
-
-                err = WEAVE_NO_ERROR; // No exception, just return 0.
-                result = 0;
-            }
         });
     }
 
@@ -889,5 +802,25 @@
     return err;
 }
 
+- (WEAVE_ERROR)deleteData:(NSString *)path
+{
+    __block WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    WDM_LOG_METHOD_SIG();
+
+    VerifyOrExit(NULL != _mWeaveCppGenericTraitUpdatableDataSink, err = WEAVE_ERROR_INCORRECT_STATE);
+
+    // need this bracket to use Verify macros
+    {
+        // we use sync so the result is immediately available to the caller upon return
+        dispatch_sync(_mWeaveWorkQueue, ^() {
+            err = _mWeaveCppGenericTraitUpdatableDataSink->DeleteData([path UTF8String]);
+        });
+    }
+
+exit:
+    return err;
+}
+
 @end
 #endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
diff --git a/src/device-manager/cocoa/NLWdmClient.h b/src/device-manager/cocoa/NLWdmClient.h
index d276574..b01b748 100644
--- a/src/device-manager/cocoa/NLWdmClient.h
+++ b/src/device-manager/cocoa/NLWdmClient.h
@@ -75,7 +75,11 @@
 
 /**
  * Begins a flush of all trait data. The result of this operation can be observed through the CompletionHandler and
- * failureHandler
+ * failureHandler, when operation completes, onWdmClientFlushUpdateComplete is called, application would receive statusResultsList,
+ * if it is empty, it means success without failed path, if anything inside, the array member could be NLWdmClientFlushUpdateError(local client error)
+ * or NLWdmClientFlushUpdateDeviceStatus(remote device status), application can use the path and dataSink from the above member to clear
+ * particular data or skip the error if necessary. When operation fails, it usually means the operation cannot complete at all, for example
+ * communication or protocol issue, onWdmClientError would be called.
  */
 - (void)flushUpdate:(WdmClientCompletionBlock)completionHandler failure:(WdmClientFailureBlock)failureHandler;
 
diff --git a/src/device-manager/cocoa/NLWdmClient.mm b/src/device-manager/cocoa/NLWdmClient.mm
index d50ee8f..58f9a63 100644
--- a/src/device-manager/cocoa/NLWdmClient.mm
+++ b/src/device-manager/cocoa/NLWdmClient.mm
@@ -47,6 +47,8 @@
 #import "NLGenericTraitUpdatableDataSink_Protected.h"
 #import "NLResourceIdentifier.h"
 #import "NLResourceIdentifier_Protected.h"
+#import "NLWdmClientFlushUpdateError.h"
+#import "NLWdmClientFlushUpdateDeviceStatusError.h"
 
 using namespace nl::Weave::Profiles;
 using namespace nl::Weave::Profiles::DataManagement;
@@ -181,18 +183,18 @@
     return result;
 }
 
-static void handleWdmClientComplete(void * wdmClient, void * reqState)
+static void onWdmClientComplete(void * appState, void * reqState)
 {
-    WDM_LOG_DEBUG(@"handleWdmClientComplete");
+    WDM_LOG_DEBUG(@"onWdmClientComplete");
 
     NLWdmClient * client = (__bridge NLWdmClient *) reqState;
     [client dispatchAsyncCompletionBlock:nil];
 }
 
-static void handleWdmClientError(
-    void * wdmClient, void * appReqState, WEAVE_ERROR code, nl::Weave::DeviceManager::DeviceStatus * devStatus)
+static void onWdmClientError(
+    void * appState, void * appReqState, WEAVE_ERROR code, nl::Weave::DeviceManager::DeviceStatus * devStatus)
 {
-    WDM_LOG_DEBUG(@"handleWdmClientError");
+    WDM_LOG_DEBUG(@"onWdmClientError");
 
     NSError * error = nil;
     NSDictionary * userInfo = nil;
@@ -225,6 +227,47 @@
     [client dispatchAsyncDefaultFailureBlock:error];
 }
 
+static void onWdmClientFlushUpdateComplete(
+    void * appState, void * appReqState, uint16_t pathCount, nl::Weave::DeviceManager::WdmClientFlushUpdateStatus * statusResults)
+{
+    WDM_LOG_DEBUG(@"onWdmClientFlushUpdateComplete");
+
+    NLWdmClient * client = (__bridge NLWdmClient *) appReqState;
+
+    NSMutableArray * statusResultsList = [NSMutableArray arrayWithCapacity:pathCount];
+    NLGenericTraitUpdatableDataSink * dataSink = nil;
+    WDM_LOG_DEBUG(@"Failed path Counts = %u\n", pathCount);
+
+    for (uint32_t i = 0; i < pathCount; i++) {
+        dataSink = [client getDataSink:(long long) statusResults[i].mpDataSink];
+        if (dataSink == nil) {
+            WDM_LOG_DEBUG(@"unexpected, trait %d does not exist in traitMap", i);
+        }
+        if (statusResults[i].mErrorCode == WEAVE_ERROR_STATUS_REPORT_RECEIVED) {
+            NLWdmClientFlushUpdateDeviceStatusError * statusError = [[NLWdmClientFlushUpdateDeviceStatusError alloc]
+                initWithProfileId:statusResults[i].mDevStatus.StatusProfileId
+                       statusCode:statusResults[i].mDevStatus.StatusCode
+                        errorCode:statusResults[i].mDevStatus.SystemErrorCode
+                     statusReport:[client statusReportToString:statusResults[i].mDevStatus.StatusProfileId
+                                                    statusCode:statusResults[i].mDevStatus.StatusCode]
+                             path:[NSString stringWithUTF8String:statusResults[i].mpPath]
+                         dataSink:dataSink];
+
+            [statusResultsList addObject:statusError];
+        } else {
+            NLWdmClientFlushUpdateError * weaveError = [[NLWdmClientFlushUpdateError alloc]
+                initWithWeaveError:statusResults[i].mErrorCode
+                            report:[NSString stringWithUTF8String:nl::ErrorStr(statusResults[i].mErrorCode)]
+                              path:[NSString stringWithUTF8String:statusResults[i].mpPath]
+                          dataSink:dataSink];
+            [statusResultsList addObject:weaveError];
+        }
+    }
+
+    NSLog(@"statusResultsList is: %@", statusResultsList);
+    [client dispatchAsyncCompletionBlockWithResults:statusResultsList];
+}
+
 - (void)markTransactionCompleted
 {
     _mRequestName = nil;
@@ -299,6 +342,19 @@
     }
 }
 
+- (void)dispatchAsyncCompletionBlockWithResults:(id)error
+{
+    WdmClientCompletionBlock completionHandler = _mCompletionHandler;
+
+    [self markTransactionCompleted];
+
+    if (nil != completionHandler) {
+        dispatch_async(_mAppCallbackQueue, ^() {
+            completionHandler(_owner, error);
+        });
+    }
+}
+
 - (NSString *)toErrorString:(WEAVE_ERROR)err
 {
     WDM_LOG_METHOD_SIG();
@@ -382,6 +438,12 @@
     }
 }
 
+- (NLGenericTraitUpdatableDataSink *)getDataSink:(long long)traitInstancePtr;
+{
+    NSString * address = [NSString stringWithFormat:@"%lld", traitInstancePtr];
+    return (NLGenericTraitUpdatableDataSink *)[_mTraitMap objectForKey:address];
+}
+
 - (void)setNodeId:(uint64_t)nodeId;
 {
     WDM_LOG_METHOD_SIG();
@@ -444,7 +506,7 @@
             _mFailureHandler = [failureHandler copy];
 
             WEAVE_ERROR err
-                = _mWeaveCppWdmClient->FlushUpdate((__bridge void *) self, handleWdmClientComplete, handleWdmClientError);
+                = _mWeaveCppWdmClient->FlushUpdate((__bridge void *) self, onWdmClientFlushUpdateComplete, onWdmClientError);
 
             if (WEAVE_NO_ERROR != err) {
                 [self dispatchAsyncDefaultFailureBlockWithCode:err];
@@ -471,8 +533,7 @@
             _mCompletionHandler = [completionHandler copy];
             _mFailureHandler = [failureHandler copy];
 
-            WEAVE_ERROR err
-                = _mWeaveCppWdmClient->RefreshData((__bridge void *) self, handleWdmClientComplete, handleWdmClientError, NULL);
+            WEAVE_ERROR err = _mWeaveCppWdmClient->RefreshData((__bridge void *) self, onWdmClientComplete, onWdmClientError, NULL);
 
             if (WEAVE_NO_ERROR != err) {
                 [self dispatchAsyncDefaultFailureBlockWithCode:err];
diff --git a/src/device-manager/cocoa/NLWdmClientFlushUpdateDeviceStatusError.h b/src/device-manager/cocoa/NLWdmClientFlushUpdateDeviceStatusError.h
new file mode 100644
index 0000000..23cc4d8
--- /dev/null
+++ b/src/device-manager/cocoa/NLWdmClientFlushUpdateDeviceStatusError.h
@@ -0,0 +1,44 @@
+/*
+ *
+ *    Copyright (c) 2020 Google, LLC.
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+/**
+ *    @file
+ *      Objective-C representation of a device status for WdmClient flush update operation
+ *
+ */
+
+#import <Foundation/Foundation.h>
+
+#import "NLProfileStatusError.h"
+#import "NLGenericTraitUpdatableDataSink.h"
+#import "NLGenericTraitUpdatableDataSink.h"
+
+@interface NLWdmClientFlushUpdateDeviceStatusError : NLProfileStatusError
+
+@property (nonatomic, readonly) NSString * path;
+@property (nonatomic, readonly) NLGenericTraitUpdatableDataSink * dataSink;
+
+- (id)initWithProfileId:(uint32_t)profileId
+             statusCode:(uint16_t)statusCode
+              errorCode:(uint32_t)errorCode
+           statusReport:(NSString *)statusReport
+                   path:(NSString *)path
+               dataSink:(NLGenericTraitUpdatableDataSink *)dataSink;
+- (NSInteger)translateErrorCode;
+
+@end
diff --git a/src/device-manager/cocoa/NLWdmClientFlushUpdateDeviceStatusError.mm b/src/device-manager/cocoa/NLWdmClientFlushUpdateDeviceStatusError.mm
new file mode 100644
index 0000000..5432d08
--- /dev/null
+++ b/src/device-manager/cocoa/NLWdmClientFlushUpdateDeviceStatusError.mm
@@ -0,0 +1,65 @@
+/*
+ *
+ *    Copyright (c) 2020 Google, LLC.
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+/**
+ *    @file
+ *      Objective-C representation of a device status for WdmClient flush update operation
+ *
+ */
+
+// Note that the choice of namespace alias must be made up front for each and every compile unit
+// This is because many include paths could set the default alias to unintended target.
+
+#import "NLProfileStatusError.h"
+#import "NLWdmClientFlushUpdateDeviceStatusError.h"
+
+@interface NLWdmClientFlushUpdateDeviceStatusError () {
+    NSString * _statusReport;
+}
+
+@end
+
+@implementation NLWdmClientFlushUpdateDeviceStatusError
+
+- (id)initWithProfileId:(uint32_t)profileId
+             statusCode:(uint16_t)statusCode
+              errorCode:(uint32_t)errorCode
+           statusReport:(NSString *)statusReport
+                   path:(NSString *)path
+               dataSink:(NLGenericTraitUpdatableDataSink*) dataSink
+{
+    self = [super initWithProfileId:profileId statusCode:statusCode errorCode:errorCode statusReport:statusReport];
+    if (self)
+    {
+        _path = path;
+        _dataSink = dataSink;
+    }
+    return self;
+}
+
+- (NSString *)description
+{
+    NSString * emptyStatusReport =
+            [NSString stringWithFormat:@"No StatusReport available. profileId = %ld, statusCode = %ld, SysErrorCode = %ld, failed path is %@ ",
+                                       (long) self.profileId, (long) self.statusCode, (long) self.errorCode, _path];
+
+    return _statusReport ? ([NSString stringWithFormat:@"%@, SysErrorCode = %ld, failed path is %@", _statusReport, (long) self.errorCode, _path])
+                         : emptyStatusReport;
+}
+
+@end
diff --git a/src/device-manager/cocoa/NLWdmClientFlushUpdateError.h b/src/device-manager/cocoa/NLWdmClientFlushUpdateError.h
new file mode 100644
index 0000000..bc18d5b
--- /dev/null
+++ b/src/device-manager/cocoa/NLWdmClientFlushUpdateError.h
@@ -0,0 +1,41 @@
+/*
+ *
+ *    Copyright (c) 2020 Google, LLC.
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+/**
+ *    @file
+ *      Objective-C representation of a local client error for WdmClient flush update operation
+ *
+ */
+
+#import <Foundation/Foundation.h>
+#import "NLWeaveDeviceManagerTypes.h"
+#import "NLWeaveErrorCodes.h"
+#import "NLWeaveError.h"
+#import "NLGenericTraitUpdatableDataSink.h"
+
+@interface NLWdmClientFlushUpdateError : NLWeaveError
+
+@property (nonatomic, readonly) NSString * path;
+@property (nonatomic, readonly) NLGenericTraitUpdatableDataSink * dataSink;
+
+- (id)initWithWeaveError:(WEAVE_ERROR)weaveError
+                  report:(NSString *)report
+                    path:(NSString *)path
+                dataSink:(NLGenericTraitUpdatableDataSink*) dataSink;
+
+@end
diff --git a/src/device-manager/cocoa/NLWdmClientFlushUpdateError.mm b/src/device-manager/cocoa/NLWdmClientFlushUpdateError.mm
new file mode 100644
index 0000000..8c9bb8d
--- /dev/null
+++ b/src/device-manager/cocoa/NLWdmClientFlushUpdateError.mm
@@ -0,0 +1,57 @@
+/*
+ *
+ *    Copyright (c) 2020 Google, LLC.
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+/**
+ *    @file
+ *      Translation of WdmClientFlushUpdate errors into native Objective C types.
+ *
+ */
+
+#import "NLWeaveError_Protected.h"
+#import "NLWdmClientFlushUpdateError.h"
+
+@interface NLWdmClientFlushUpdateError () {
+    NSString * _errorReport;
+}
+@end
+
+@implementation NLWdmClientFlushUpdateError
+
+- (id)initWithWeaveError:(WEAVE_ERROR)weaveError
+                  report:(NSString *)report
+                    path:(NSString *)path
+                dataSink:(NLGenericTraitUpdatableDataSink*) dataSink
+{
+    self = [super initWithWeaveError:weaveError report:report];
+    if (self)
+    {
+        _path = path;
+        _dataSink = dataSink;
+    }
+    return self;
+}
+
+- (NSString *)description
+{
+    NSString * emptyErrorReport = [NSString
+        stringWithFormat:@"No Error information available. errorCode = %ld (0x%lx), failed path is %@", (long) self.errorCode, (long) self.errorCode, _path];
+
+    return _errorReport ? ([NSString stringWithFormat:@"%@ - errorCode: %ld, failed path is %@", _errorReport, (long) self.errorCode, _path])
+                        : emptyErrorReport;
+}
+@end
diff --git a/src/device-manager/cocoa/NLWdmClient_Protected.h b/src/device-manager/cocoa/NLWdmClient_Protected.h
index ae11451..d495f0f 100644
--- a/src/device-manager/cocoa/NLWdmClient_Protected.h
+++ b/src/device-manager/cocoa/NLWdmClient_Protected.h
@@ -38,5 +38,6 @@
 - (NSString *)statusReportToString:(NSUInteger)profileId statusCode:(NSInteger)statusCode;
 
 - (void)removeDataSinkRef:(long long)traitInstancePtr;
+- (NLGenericTraitUpdatableDataSink *)getDataSink:(long long)traitInstancePtr;
 
 @end
diff --git a/src/device-manager/java/Makefile.am b/src/device-manager/java/Makefile.am
index f3f1be5..8b891d6 100644
--- a/src/device-manager/java/Makefile.am
+++ b/src/device-manager/java/Makefile.am
@@ -110,6 +110,8 @@
     nl/Weave/DataManagement/GenericTraitUpdatableDataSinkImpl.java \
     nl/Weave/DataManagement/WdmClientFactory.java           \
     nl/Weave/DataManagement/ResourceIdentifier.java         \
+    nl/Weave/DataManagement/WdmClientFlushUpdateException.java          \
+    nl/Weave/DataManagement/WdmClientFlushUpdateDeviceException.java    \
     $(NULL)
 
 WeaveDeviceManager_jar_JFLAGS                      = -source 6 -target 6
diff --git a/src/device-manager/java/WeaveDeviceManager-JNI.cpp b/src/device-manager/java/WeaveDeviceManager-JNI.cpp
index afda373..33773f1 100644
--- a/src/device-manager/java/WeaveDeviceManager-JNI.cpp
+++ b/src/device-manager/java/WeaveDeviceManager-JNI.cpp
@@ -104,6 +104,8 @@
 static jclass sWirelessRegulatoryConfigCls = NULL;
 static jclass sWeaveDeviceManagerCls = NULL;
 static jclass sWeaveStackCls = NULL;
+static jclass sWdmClientFlushUpdateDeviceExceptionCls = NULL;
+static jclass sWdmClientFlushUpdateExceptionCls = NULL;
 
 extern "C" {
     NL_DLL_EXPORT jint JNI_OnLoad(JavaVM *jvm, void *reserved);
@@ -201,6 +203,7 @@
     NL_DLL_EXPORT jbyteArray Java_nl_Weave_DataManagement_GenericTraitUpdatableDataSinkImpl_getBytes(JNIEnv *env, jobject self, jlong genericTraitUpdatableDataSinkPtr, jstring path);
     NL_DLL_EXPORT jobjectArray Java_nl_Weave_DataManagement_GenericTraitUpdatableDataSinkImpl_getStringArray(JNIEnv *env, jobject self, jlong genericTraitUpdatableDataSinkPtr, jstring path);
     NL_DLL_EXPORT jlong Java_nl_Weave_DataManagement_GenericTraitUpdatableDataSinkImpl_getVersion(JNIEnv *env, jobject self, jlong genericTraitUpdatableDataSinkPtr);
+    NL_DLL_EXPORT void Java_nl_Weave_DataManagement_GenericTraitUpdatableDataSinkImpl_deleteData(JNIEnv *env, jobject self, jlong genericTraitUpdatableDataSinkPtr, jstring path);
 #endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
 };
 
@@ -214,8 +217,6 @@
 static void HandleDeviceEnumerationResponse(WeaveDeviceManager *deviceMgr, void *reqState, const DeviceDescription::WeaveDeviceDescriptor *devdesc, IPAddress deviceAddr, InterfaceId deviceIntf);
 static void HandleGenericOperationComplete(jobject obj, void *reqState);
 static void HandleSimpleOperationComplete(WeaveDeviceManager *deviceMgr, void *reqState);
-static void HandleWdmClientComplete(void *context, void *reqState);
-static void HandleGenericTraitUpdatableDataSinkComplete(void *context, void *reqState);
 static void HandleNotifyWeaveConnectionClosed(BLE_CONNECTION_OBJECT connObj);
 static bool HandleSendCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t *svcId, const uint8_t *charId, const uint8_t *characteristicData, uint32_t characteristicDataLen);
 static bool HandleSubscribeCharacteristic(BLE_CONNECTION_OBJECT connObj, const uint8_t *svcId, const uint8_t *charId);
@@ -225,12 +226,8 @@
 static void HandleGetWirelessRegulatoryConfigComplete(WeaveDeviceManager *deviceMgr, void *reqState, const WirelessRegConfig * regConfig);
 static bool HandleCloseConnection(BLE_CONNECTION_OBJECT connObj);
 static uint16_t HandleGetMTU(BLE_CONNECTION_OBJECT connObj);
-static void HandleGenericError(jobject obj, void *reqState, WEAVE_ERROR deviceErr, DeviceStatus *devStatus);
-static void HandleError(WeaveDeviceManager *deviceMgr, void *reqState, WEAVE_ERROR err, DeviceStatus *devStatus);
-#if WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
-static void HandleWdmClientError(void *appState, void *reqState, WEAVE_ERROR deviceErr, DeviceStatus *devStatus);
-static void HandleGenericTraitUpdatableDataSinkError(void *context, void *reqState, WEAVE_ERROR deviceErr, DeviceStatus *devStatus);
-#endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+static void HandleGenericError(jobject obj, void *reqState, WEAVE_ERROR deviceMgrErr, DeviceStatus *devStatus);
+static void HandleError(WeaveDeviceManager *deviceMgr, void *reqState, WEAVE_ERROR deviceMgrErr, DeviceStatus *devStatus);
 static void ThrowError(JNIEnv *env, WEAVE_ERROR errToThrow);
 static void ReportError(JNIEnv *env, WEAVE_ERROR cbErr, const char *cbName);
 static void *IOThreadMain(void *arg);
@@ -253,18 +250,27 @@
 static WEAVE_ERROR J2N_WirelessRegulatoryConfig(JNIEnv *env, jobject inRegConfig, WirelessRegConfig & outRegConfig);
 static WEAVE_ERROR N2J_WirelessRegulatoryConfig(JNIEnv *env, const WirelessRegConfig& inRegConfig, jobject& outRegConfig);
 static WEAVE_ERROR N2J_Error(JNIEnv *env, WEAVE_ERROR inErr, jthrowable& outEx);
-static WEAVE_ERROR N2J_DeviceStatus(JNIEnv *env, DeviceStatus& devStatus, jthrowable& outEx);
 static WEAVE_ERROR J2N_ResourceIdentifier(JNIEnv *env, jobject inResourceIdentifier, ResourceIdentifier& outResourceIdentifier);
 static WEAVE_ERROR GetClassRef(JNIEnv *env, const char *clsType, jclass& outCls);
 static WEAVE_ERROR J2N_StdString(JNIEnv *env, jstring inString,  std::string& outString);
+template<typename GetElementFunct>
+WEAVE_ERROR N2J_GenericArray(JNIEnv *env, uint32_t arrayLen, jclass arrayElemCls, jobjectArray& outArray, GetElementFunct getElem);
 
+#if WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+static void HandleWdmClientComplete(void *context, void *reqState);
+static void HandleGenericTraitUpdatableDataSinkComplete(void *context, void *reqState, DeviceStatus *deviceStatus);
+static void HandleWdmClientError(void *appState, void *reqState, WEAVE_ERROR deviceMgrErr, DeviceStatus *devStatus);
+static void HandleGenericTraitUpdatableDataSinkError(void *context, void *reqState, WEAVE_ERROR deviceMgrErr, DeviceStatus *devStatus);
+static void HandleWdmClientFlushUpdateComplete(void *context, void *reqState, uint16_t pathCount, WdmClientFlushUpdateStatus *statusResults);
+static WEAVE_ERROR N2J_DeviceStatus(JNIEnv *env, DeviceStatus& devStatus, jthrowable& outEx);
+static WEAVE_ERROR N2J_WdmClientFlushUpdateError(JNIEnv *env, WEAVE_ERROR inErr, jobject& outEx, const char * path, TraitDataSink * dataSink);
+static WEAVE_ERROR N2J_WdmClientFlushUpdateDeviceStatus(JNIEnv *env, DeviceStatus& devStatus, jobject& outEx, const char * path, TraitDataSink * dataSink);
 static void EngineEventCallback(void * const aAppState,
                                 SubscriptionEngine::EventID aEvent,
                                 const SubscriptionEngine::InEventParam & aInParam, SubscriptionEngine::OutEventParam & aOutParam);
 static void BindingEventCallback (void * const apAppState, const nl::Weave::Binding::EventType aEvent,
                                   const nl::Weave::Binding::InEventParam & aInParam, nl::Weave::Binding::OutEventParam & aOutParam);
-template<typename GetElementFunct>
-WEAVE_ERROR N2J_GenericArray(JNIEnv *env, uint32_t arrayLen, jclass arrayElemCls, jobjectArray& outArray, GetElementFunct getElem);
+#endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
 
 #if CURRENTLY_UNUSED
 static WEAVE_ERROR J2N_EnumVal(JNIEnv *env, jobject enumObj, int& outVal);
@@ -304,6 +310,10 @@
     SuccessOrExit(err);
     err = GetClassRef(env, "nl/Weave/DeviceManager/WeaveStack", sWeaveStackCls);
     SuccessOrExit(err);
+    err = GetClassRef(env, "nl/Weave/DataManagement/WdmClientFlushUpdateDeviceException", sWdmClientFlushUpdateDeviceExceptionCls);
+    SuccessOrExit(err);
+    err = GetClassRef(env, "nl/Weave/DataManagement/WdmClientFlushUpdateException", sWdmClientFlushUpdateExceptionCls);
+    SuccessOrExit(err);
     WeaveLogProgress(DeviceManager, "Java class references loaded.");
 
     // Initialize the lock that will be used to protect the stack.  Note that this needs to allow recursive acquisition.
@@ -2377,6 +2387,82 @@
     jobject self = (jobject)sink->mpAppState;
     HandleGenericOperationComplete(self, reqState);
 }
+
+void HandleWdmClientError(void *context, void *reqState, WEAVE_ERROR deviceMgrErr, DeviceStatus *devStatus)
+{
+    WdmClient * wdmClient = reinterpret_cast<WdmClient *>(context);
+    jobject self = (jobject)wdmClient->mpAppState;
+    HandleGenericError(self, reqState, deviceMgrErr, devStatus);
+}
+
+void HandleGenericTraitUpdatableDataSinkError(void *context, void *reqState, WEAVE_ERROR deviceMgrErr, DeviceStatus *devStatus)
+{
+    GenericTraitUpdatableDataSink * sink = reinterpret_cast<GenericTraitUpdatableDataSink *>(context);
+    jobject self = (jobject)sink->mpAppState;
+    HandleGenericError(self, reqState, deviceMgrErr, devStatus);
+}
+
+void HandleWdmClientFlushUpdateComplete(void *context, void *reqState, uint16_t pathCount, WdmClientFlushUpdateStatus *statusResults)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    JNIEnv *env;
+    WdmClient * wdmClient = reinterpret_cast<WdmClient *>(context);
+    jobject self = (jobject)wdmClient->mpAppState;
+    jclass wdmClientCls;
+    jclass java_lang_Throwable = NULL;
+    jmethodID method;
+    jobjectArray exceptionArrayObj = NULL;
+    bool localFramePushed = false;
+
+    sJVM->GetEnv((void **)&env, JNI_VERSION_1_2);
+    WeaveLogProgress(DeviceManager, "Received response to FlushUpdate request, number of failed updated path is %d", pathCount);
+
+    if (env->PushLocalFrame(WDM_JNI_CALLBACK_LOCAL_REF_COUNT) == 0)
+    {
+        localFramePushed = true;
+    }
+
+    VerifyOrExit(localFramePushed, err = WEAVE_ERROR_NO_MEMORY);
+
+    java_lang_Throwable = env->FindClass("java/lang/Throwable");
+    VerifyOrExit(java_lang_Throwable != NULL, err = WDM_JNI_ERROR_TYPE_NOT_FOUND);
+
+    err = N2J_GenericArray(env, pathCount, java_lang_Throwable, exceptionArrayObj,
+    [&statusResults](JNIEnv *_env, uint32_t index, jobject& ex) -> WEAVE_ERROR
+    {
+        WEAVE_ERROR _err = WEAVE_NO_ERROR;
+        if (statusResults[index].mErrorCode == WEAVE_ERROR_STATUS_REPORT_RECEIVED)
+        {
+            _err = N2J_WdmClientFlushUpdateDeviceStatus(_env, statusResults[index].mDevStatus, ex, statusResults->mpPath, statusResults->mpDataSink);
+        }
+        else
+        {
+            _err = N2J_WdmClientFlushUpdateError(_env, statusResults[index].mErrorCode, ex, statusResults->mpPath, statusResults->mpDataSink);
+        }
+        return _err;
+    });
+    SuccessOrExit(err);
+
+    wdmClientCls = env->GetObjectClass(self);
+    VerifyOrExit(wdmClientCls != NULL, err = WDM_JNI_ERROR_TYPE_NOT_FOUND);
+
+    method = env->GetMethodID(wdmClientCls, "onFlushUpdateComplete", "([Ljava/lang/Throwable;)V");
+    VerifyOrExit(method != NULL, err = WDM_JNI_ERROR_METHOD_NOT_FOUND);
+
+    WeaveLogProgress(DeviceManager, "Calling Java onFlushUpdateComplete method");
+
+    env->ExceptionClear();
+    env->CallVoidMethod(self, method, exceptionArrayObj);
+    VerifyOrExit(!env->ExceptionCheck(), err = WDM_JNI_ERROR_EXCEPTION_THROWN);
+
+exit:
+    if (err != WEAVE_NO_ERROR)
+        ReportError(env, err, __FUNCTION__);
+    env->ExceptionClear();
+    if (localFramePushed)
+        env->PopLocalFrame(NULL);
+}
+
 #endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
 void HandleNotifyWeaveConnectionClosed(BLE_CONNECTION_OBJECT connObj)
 {
@@ -2757,7 +2843,7 @@
     return mtu;
 }
 
-void HandleGenericError(jobject obj, void *reqState, WEAVE_ERROR deviceErr, DeviceStatus *devStatus)
+void HandleGenericError(jobject obj, void *reqState, WEAVE_ERROR deviceMgrErr, DeviceStatus *devStatus)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     JNIEnv *env;
@@ -2775,14 +2861,14 @@
         localFramePushed = true;
     VerifyOrExit(localFramePushed, err = WEAVE_ERROR_NO_MEMORY);
 
-    if (deviceErr == WEAVE_ERROR_STATUS_REPORT_RECEIVED && devStatus != NULL)
+    if (deviceMgrErr == WEAVE_ERROR_STATUS_REPORT_RECEIVED && devStatus != NULL)
     {
         err = N2J_DeviceStatus(env, *devStatus, ex);
         SuccessOrExit(err);
     }
     else
     {
-        err = N2J_Error(env, deviceErr, ex);
+        err = N2J_Error(env, deviceMgrErr, ex);
         SuccessOrExit(err);
     }
 
@@ -2806,28 +2892,12 @@
         env->PopLocalFrame(NULL);
 }
 
-void HandleError(WeaveDeviceManager *deviceMgr, void *reqState, WEAVE_ERROR deviceErr, DeviceStatus *devStatus)
+void HandleError(WeaveDeviceManager *deviceMgr, void *reqState, WEAVE_ERROR deviceMgrErr, DeviceStatus *devStatus)
 {
     jobject self = (jobject)deviceMgr->AppState;
-    HandleGenericError(self, reqState, deviceErr, devStatus);
+    HandleGenericError(self, reqState, deviceMgrErr, devStatus);
 }
 
-#if WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
-void HandleWdmClientError(void *context, void *reqState, WEAVE_ERROR deviceErr, DeviceStatus *devStatus)
-{
-    WdmClient * wdmClient = reinterpret_cast<WdmClient *>(context);
-    jobject self = (jobject)wdmClient->mpAppState;
-    HandleGenericError(self, reqState, deviceErr, devStatus);
-}
-
-void HandleGenericTraitUpdatableDataSinkError(void *context, void *reqState, WEAVE_ERROR deviceErr, DeviceStatus *devStatus)
-{
-    GenericTraitUpdatableDataSink * sink = reinterpret_cast<GenericTraitUpdatableDataSink *>(context);
-    jobject self = (jobject)sink->mpAppState;
-    HandleGenericError(self, reqState, deviceErr, devStatus);
-}
-#endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
-
 void ThrowError(JNIEnv *env, WEAVE_ERROR errToThrow)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
@@ -3632,6 +3702,63 @@
     return err;
 }
 
+WEAVE_ERROR N2J_WdmClientFlushUpdateError(JNIEnv *env, WEAVE_ERROR inErr, jobject& outEx, const char * path, TraitDataSink * dataSink)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    jmethodID constructor;
+    const char *errStr = NULL;
+    jstring errStrObj = NULL;
+    jstring pathStrObj = NULL;
+
+    constructor = env->GetMethodID(sWdmClientFlushUpdateExceptionCls, "<init>", "(ILjava/lang/String;Ljava/lang/String;J)V");
+    VerifyOrExit(constructor != NULL, err = WDM_JNI_ERROR_METHOD_NOT_FOUND);
+
+    switch (inErr)
+    {
+        case WDM_JNI_ERROR_TYPE_NOT_FOUND            : errStr = "WdmClient Error: JNI type not found"; break;
+        case WDM_JNI_ERROR_METHOD_NOT_FOUND          : errStr = "WdmClient Error: JNI method not found"; break;
+        case WDM_JNI_ERROR_FIELD_NOT_FOUND           : errStr = "WdmClient Error: JNI field not found"; break;
+        default:                                     ; errStr = nl::ErrorStr(inErr); break;
+    }
+
+    errStrObj = (errStr != NULL) ? env->NewStringUTF(errStr) : NULL;
+    pathStrObj = (path != NULL) ? env->NewStringUTF(path) : NULL;
+
+    env->ExceptionClear();
+    outEx = env->NewObject(sWdmClientFlushUpdateExceptionCls, constructor, (jint)inErr, errStrObj, pathStrObj, (jlong)dataSink);
+    VerifyOrExit(!env->ExceptionCheck(), err = WDM_JNI_ERROR_EXCEPTION_THROWN);
+
+exit:
+    env->DeleteLocalRef(errStrObj);
+    env->DeleteLocalRef(pathStrObj);
+    return err;
+}
+
+WEAVE_ERROR N2J_WdmClientFlushUpdateDeviceStatus(JNIEnv *env, DeviceStatus& devStatus, jobject& outEx, const char * path, TraitDataSink * dataSink)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    jmethodID constructor;
+    const char *errStr = NULL;
+    jstring errStrObj = NULL;
+    jstring pathStrObj = NULL;
+
+    constructor = env->GetMethodID(sWdmClientFlushUpdateDeviceExceptionCls, "<init>", "(IIILjava/lang/String;Ljava/lang/String;J)V");
+    VerifyOrExit(constructor != NULL, err = WDM_JNI_ERROR_METHOD_NOT_FOUND);
+    errStr = nl::StatusReportStr(devStatus.StatusProfileId, devStatus.StatusCode);
+    errStrObj = (errStr != NULL) ? env->NewStringUTF(errStr) : NULL;
+    pathStrObj = (path != NULL) ? env->NewStringUTF(path) : NULL;
+
+    env->ExceptionClear();
+    outEx = (jthrowable)env->NewObject(sWdmClientFlushUpdateDeviceExceptionCls, constructor, (jint)devStatus.StatusCode,
+            (jint)devStatus.StatusProfileId, (jint)devStatus.SystemErrorCode, errStrObj, pathStrObj, (jlong)dataSink);
+    VerifyOrExit(!env->ExceptionCheck(), err = WDM_JNI_ERROR_EXCEPTION_THROWN);
+
+exit:
+    env->DeleteLocalRef(errStrObj);
+    env->DeleteLocalRef(pathStrObj);
+    return err;
+}
+
 WEAVE_ERROR J2N_ResourceIdentifier(JNIEnv *env, jobject inResourceIdentifier, ResourceIdentifier & outResourceIdentifier)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
@@ -3842,7 +3969,7 @@
     WeaveLogProgress(DeviceManager, "beginFlushUpdate() called");
 
     pthread_mutex_lock(&sStackLock);
-    err = wdmClient->FlushUpdate((void *)"FlushUpdate", HandleWdmClientComplete, HandleWdmClientError);
+    err = wdmClient->FlushUpdate((void *)"FlushUpdate", HandleWdmClientFlushUpdateComplete, HandleWdmClientError);
     pthread_mutex_unlock(&sStackLock);
 
     if (err != WEAVE_NO_ERROR && err != WDM_JNI_ERROR_EXCEPTION_THROWN)
@@ -4306,7 +4433,7 @@
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     const char *pPathStr = NULL;
-    jobjectArray array;
+    jobjectArray array = NULL;
     jclass java_lang_String = NULL;
     std::vector<std::string> stringVector;
 
@@ -4387,6 +4514,31 @@
     return (jlong)version;
 }
 
+NL_DLL_EXPORT void Java_nl_Weave_DataManagement_GenericTraitUpdatableDataSinkImpl_deleteData(JNIEnv *env, jobject self, jlong genericTraitUpdatableDataSinkPtr, jstring path)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    const char *pPathStr = NULL;
+    GenericTraitUpdatableDataSink *pDataSink = (GenericTraitUpdatableDataSink *)genericTraitUpdatableDataSinkPtr;
+
+    WeaveLogProgress(DeviceManager, "deleteData() called");
+
+    pPathStr = env->GetStringUTFChars(path, 0);
+    VerifyOrExit(pPathStr != NULL, err = WEAVE_ERROR_NO_MEMORY);
+
+    err = pDataSink->DeleteData(pPathStr);
+
+exit:
+    if (pPathStr != NULL)
+    {
+        env->ReleaseStringUTFChars(path, pPathStr);
+    }
+
+    if (err != WEAVE_NO_ERROR && err != WDM_JNI_ERROR_EXCEPTION_THROWN)
+    {
+        ThrowError(env, err);
+    }
+}
+
 namespace nl {
 namespace Weave {
 namespace Profiles {
diff --git a/src/device-manager/java/src/nl/Weave/DataManagement/GenericTraitUpdatableDataSink.java b/src/device-manager/java/src/nl/Weave/DataManagement/GenericTraitUpdatableDataSink.java
index a8c9427..3f2b163 100644
--- a/src/device-manager/java/src/nl/Weave/DataManagement/GenericTraitUpdatableDataSink.java
+++ b/src/device-manager/java/src/nl/Weave/DataManagement/GenericTraitUpdatableDataSink.java
@@ -36,7 +36,7 @@
 public interface GenericTraitUpdatableDataSink
 {
     /**
-     * clear trait data
+     * clear the whole trait data.
      */
     public void clear();
 
@@ -332,6 +332,9 @@
     /** Returns the version of the trait represented by this data sink. */
     public long getVersion();
 
+    /** Delete the trait property data on on particular path. */
+    public void deleteData(String path);
+
     /**
      * Begins a sync of the trait data. The result of this operation can be observed through the {@link CompletionHandler}
      * that has been assigned via {@link #setCompletionHandler}.
diff --git a/src/device-manager/java/src/nl/Weave/DataManagement/GenericTraitUpdatableDataSinkImpl.java b/src/device-manager/java/src/nl/Weave/DataManagement/GenericTraitUpdatableDataSinkImpl.java
index dc5dde7..fcc5ffc 100644
--- a/src/device-manager/java/src/nl/Weave/DataManagement/GenericTraitUpdatableDataSinkImpl.java
+++ b/src/device-manager/java/src/nl/Weave/DataManagement/GenericTraitUpdatableDataSinkImpl.java
@@ -278,6 +278,13 @@
     }
 
     @Override
+    public void deleteData(String path)
+    {
+        ensureNotClosed();
+        deleteData(mTraitInstancePtr, path);
+    }
+
+    @Override
     public void beginRefreshData()
     {
         ensureNotClosed();
@@ -371,4 +378,5 @@
     private native boolean isNull(long genericTraitUpdatableDataSinkPtr, String path);
     private native String[] getStringArray(long genericTraitUpdatableDataSinkPtr, String path);
     private native long getVersion(long genericTraitUpdatableDataSinkPtr);
+    private native void deleteData(long genericTraitUpdatableDataSinkPtr, String path);
 };
diff --git a/src/device-manager/java/src/nl/Weave/DataManagement/WdmClient.java b/src/device-manager/java/src/nl/Weave/DataManagement/WdmClient.java
index d01f7c4..ee0978e 100644
--- a/src/device-manager/java/src/nl/Weave/DataManagement/WdmClient.java
+++ b/src/device-manager/java/src/nl/Weave/DataManagement/WdmClient.java
@@ -52,7 +52,12 @@
 
     /**
      * Begins a flush of all trait data. The result of this operation can be observed through the {@link CompletionHandler}
-     * that has been assigned via {@link #setCompletionHandler}.
+     * that has been assigned via {@link #setCompletionHandler}.when operation completes, onFlushUpdateComplete is called,
+     * application would receive throwable exception list, if it is empty, it means success without failed path,
+     * if anything inside, the array member could be WdmClientFlushUpdateException(local client error)
+     * or WdmClientFlushUpdateDeviceException(remote device status), application can use the path and dataSink from the above member to clear
+     * particular data or skip the error if necessary. When operation fails, it usually means the operation cannot complete at all, for example
+     * communication or protocol issue, onError would be called.
      */
     public void beginFlushUpdate();
 
@@ -65,9 +70,11 @@
     public CompletionHandler getCompletionHandler();
     public void setCompletionHandler(CompletionHandler compHandler);
 
+    public GenericTraitUpdatableDataSink getDataSink(long traitInstancePtr);
+
     public interface CompletionHandler
     {
-        void onFlushUpdateComplete();
+        void onFlushUpdateComplete(Throwable[] exceptions, WdmClient wdmClient);
         void onRefreshDataComplete();
         void onError(Throwable err);
     }
diff --git a/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientFlushUpdateDeviceException.java b/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientFlushUpdateDeviceException.java
new file mode 100644
index 0000000..188ad26
--- /dev/null
+++ b/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientFlushUpdateDeviceException.java
@@ -0,0 +1,51 @@
+/*
+ *
+ *    Copyright (c) 2020 Google, LLC.
+ *    All rights reserved.
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+package nl.Weave.DataManagement;
+import nl.Weave.DeviceManager.WeaveDeviceException;
+
+/** Represents a exception that occurred on a Weave device during the WdmClient FlushUpdate operation.
+ */
+public class WdmClientFlushUpdateDeviceException extends WeaveDeviceException {
+    public WdmClientFlushUpdateDeviceException (int statusCode, int profileId, int sysErrorCode, String description, String pathStr, long dataSink) {
+        super(statusCode, profileId, sysErrorCode, description != null ? description : String.format("Error Code %d, Profile Id %d, StatusCode %d, path %s", sysErrorCode, profileId, statusCode, pathStr));
+        path = pathStr;
+        dataSinkPtr = dataSink;
+    }
+
+    /**
+     * Get data sink
+     *
+     * @param wdmClient weave data management client
+     *
+     */
+    public GenericTraitUpdatableDataSink getDataSink(WdmClient wdmClient)
+    {
+        return wdmClient.getDataSink(dataSinkPtr);
+    }
+
+    /**
+     * A flushed path
+     */
+    public final String path;
+
+    /**
+     * A data sink reference related to this exception
+     */
+    private final long dataSinkPtr;
+}
diff --git a/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientFlushUpdateException.java b/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientFlushUpdateException.java
new file mode 100644
index 0000000..db45c72
--- /dev/null
+++ b/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientFlushUpdateException.java
@@ -0,0 +1,53 @@
+/*
+
+    Copyright (c) 2020 Google, LLC.
+    All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+ */
+
+package nl.Weave.DataManagement;
+import nl.Weave.DeviceManager.WeaveDeviceManagerException;
+
+/** Represents a exception that occurred on the client side during the WdmClient FlushUpdate operation.
+ */
+public class WdmClientFlushUpdateException extends WeaveDeviceManagerException
+{
+    public WdmClientFlushUpdateException(int errorCode, String message, String pathStr, long dataSink)
+    {
+        super(errorCode, message != null ? message : String.format("Error Code %d, Path %s", errorCode, pathStr));
+        path      = pathStr;
+        dataSinkPtr  = dataSink;
+    }
+
+    /**
+     * Get data sink
+     *
+     * @param wdmClient weave data management client
+     *
+     */
+    public GenericTraitUpdatableDataSink getDataSink(WdmClient wdmClient)
+    {
+        return wdmClient.getDataSink(dataSinkPtr);
+    }
+
+    /**
+     * A flushed path
+     */
+    public final String path;
+
+    /**
+     * A data sink reference related to this exception
+     */
+    private final long dataSinkPtr;
+}
diff --git a/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientImpl.java b/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientImpl.java
index dea5311..5418bb8 100644
--- a/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientImpl.java
+++ b/src/device-manager/java/src/nl/Weave/DataManagement/WdmClientImpl.java
@@ -27,11 +27,11 @@
 import android.util.Log;
 import java.math.BigInteger;
 import java.util.EnumSet;
-import java.util.Random;
 import java.util.HashMap;
-import java.util.Map;
 import java.util.Iterator;
+import java.util.Map;
 import java.util.Objects;
+import java.util.Random;
 
 public class WdmClientImpl implements WdmClient
 {
@@ -135,6 +135,16 @@
         mCompHandler = compHandler;
     }
 
+    public GenericTraitUpdatableDataSink getDataSink(long traitInstancePtr)
+    {
+        GenericTraitUpdatableDataSink trait = null;
+        if (mTraitMap != null) {
+          trait = mTraitMap.get(traitInstancePtr);
+        }
+
+        return trait;
+    }
+
     // ----- Protected Members -----
     protected void removeDataSinkRef(long traitInstancePtr)
     {
@@ -159,9 +169,9 @@
         requireCompletionHandler().onError(err);
     }
 
-    private void onFlushUpdateComplete()
+    private void onFlushUpdateComplete(Throwable[] exceptions)
     {
-        requireCompletionHandler().onFlushUpdateComplete();
+        requireCompletionHandler().onFlushUpdateComplete(exceptions, this);
     }
 
     private void onRefreshDataComplete()
diff --git a/src/device-manager/java/src/nl/Weave/DeviceManager/TestMain.java b/src/device-manager/java/src/nl/Weave/DeviceManager/TestMain.java
index 06cfe6f..76ad3aa 100644
--- a/src/device-manager/java/src/nl/Weave/DeviceManager/TestMain.java
+++ b/src/device-manager/java/src/nl/Weave/DeviceManager/TestMain.java
@@ -127,6 +127,7 @@
         GenericTraitUpdatableDataSink testCTrait;
 
         ResourceIdentifier resourceIdentifier = new ResourceIdentifier();
+
         localSettingsTrait = mockWdmClient.newDataSink(resourceIdentifier, 20, 0, "/");
         testCTrait = mockWdmClient.newDataSink(resourceIdentifier, 593165827, 0, "/");
         localSettingsTrait.setCompletionHandler(this);
@@ -153,6 +154,8 @@
         GenericTraitUpdatableDataSink testCTrait;
 
         ResourceIdentifier resourceIdentifier = new ResourceIdentifier();
+        int ExpectedSystemErrors[] = {0, 0, 0, 0, 0, 0};
+
         localSettingsTrait = mockWdmClient.newDataSink(resourceIdentifier, 20, 0, "/");
         testCTrait = mockWdmClient.newDataSink(resourceIdentifier, 593165827, 0, "/");
         localSettingsTrait.setCompletionHandler(this);
@@ -176,7 +179,128 @@
         System.out.println("testWdmClientDataSinkSetFlushData Test Succeeded");
     }
 
-    void testWdmClientDataSinkRefreshGetDataRefresh(WeaveDeviceManager deviceMgr)
+    void testWdmClientDataSinkSetFlushInvalidData(WeaveDeviceManager deviceMgr)
+    {
+        WdmClientFactory wdmClientFactory = new WdmClientFactory();
+        WdmClient mockWdmClient = wdmClientFactory.create(deviceMgr);
+        mockWdmClient.setCompletionHandler(this);
+
+        GenericTraitUpdatableDataSink localSettingsTrait;
+        GenericTraitUpdatableDataSink testCTrait;
+
+        ResourceIdentifier resourceIdentifier = new ResourceIdentifier();
+
+        localSettingsTrait = mockWdmClient.newDataSink(resourceIdentifier, 20, 0, "/");
+        testCTrait = mockWdmClient.newDataSink(resourceIdentifier, 593165827, 0, "/");
+        localSettingsTrait.setCompletionHandler(this);
+        testCTrait.setCompletionHandler(this);
+
+        // set invalid data in /1
+        localSettingsTrait.set("/1", 0.1);
+        testCTrait.set("/1", false);
+        testCTrait.setSigned("/2", 15);
+
+        testCTrait.setUnsigned("/3/1", -5);
+        testCTrait.set("/3/2", false);
+        testCTrait.setUnsigned("/4", -6);
+
+        TestResult = null;
+        mockWdmClient.beginFlushUpdate();
+        ExpectSuccess("FlushUpdate");
+
+        System.out.println("testWdmClientDataSinkSetFlushInvalidData Test Stage 1 Succeeded");
+
+        //flush again, expect the empty path result
+
+        TestResult = null;
+        mockWdmClient.beginFlushUpdate();
+        ExpectSuccess("FlushUpdate");
+        System.out.println("testWdmClientDataSinkSetFlushInvalidData Test Stage 2 Succeeded");
+
+        mockWdmClient.close();
+        mockWdmClient = null;
+        localSettingsTrait = null;
+        testCTrait = null;
+        System.out.println("testWdmClientDataSinkSetFlushInvalidData Test Succeeded");
+    }
+
+    void testWdmClientDataSinkSetFlushDataDeleteData(WeaveDeviceManager deviceMgr)
+    {
+        WdmClientFactory wdmClientFactory = new WdmClientFactory();
+        WdmClient mockWdmClient = wdmClientFactory.create(deviceMgr);
+        mockWdmClient.setCompletionHandler(this);
+
+        GenericTraitUpdatableDataSink localSettingsTrait;
+        GenericTraitUpdatableDataSink testCTrait;
+
+        ResourceIdentifier resourceIdentifier = new ResourceIdentifier();
+        int ExpectedSystemErrors[] = {0};
+        localSettingsTrait = mockWdmClient.newDataSink(resourceIdentifier, 20, 0, "/");
+        testCTrait = mockWdmClient.newDataSink(resourceIdentifier, 593165827, 0, "/");
+        localSettingsTrait.setCompletionHandler(this);
+        testCTrait.setCompletionHandler(this);
+
+        localSettingsTrait.set("/1", "en-US");
+        testCTrait.set("/1", false);
+        testCTrait.setSigned("/2", 15);
+        testCTrait.setUnsigned("/3/1", -5);
+        testCTrait.set("/3/2", false);
+        testCTrait.setUnsigned("/4", -5);
+
+        localSettingsTrait.deleteData("/1");
+        testCTrait.deleteData("/1");
+        testCTrait.deleteData("/2");
+        testCTrait.deleteData("/3/1");
+        testCTrait.deleteData("/3/2");
+ 
+        TestResult = null;
+        mockWdmClient.beginFlushUpdate();
+        ExpectSuccess("FlushUpdate");
+
+        mockWdmClient.close();
+        mockWdmClient = null;
+        localSettingsTrait = null;
+        testCTrait = null;
+        System.out.println("testWdmClientDataSinkSetFlushDataDeleteData Test Succeeded");
+    }
+
+    void testWdmClientDataSinkSetClearFlushData(WeaveDeviceManager deviceMgr)
+    {
+        WdmClientFactory wdmClientFactory = new WdmClientFactory();
+        WdmClient mockWdmClient = wdmClientFactory.create(deviceMgr);
+        mockWdmClient.setCompletionHandler(this);
+
+        GenericTraitUpdatableDataSink localSettingsTrait;
+        GenericTraitUpdatableDataSink testCTrait;
+
+        ResourceIdentifier resourceIdentifier = new ResourceIdentifier();
+        localSettingsTrait = mockWdmClient.newDataSink(resourceIdentifier, 20, 0, "/");
+        testCTrait = mockWdmClient.newDataSink(resourceIdentifier, 593165827, 0, "/");
+        localSettingsTrait.setCompletionHandler(this);
+        testCTrait.setCompletionHandler(this);
+
+        localSettingsTrait.set("/1", "en-US");
+        testCTrait.set("/1", false);
+        testCTrait.setSigned("/2", 15);
+        testCTrait.setUnsigned("/3/1", -5);
+        testCTrait.set("/3/2", false);
+        testCTrait.setUnsigned("/4", -5);
+
+        localSettingsTrait.clear();
+        testCTrait.clear();
+
+        TestResult = null;
+        mockWdmClient.beginFlushUpdate();
+        ExpectSuccess("FlushUpdate");
+
+        mockWdmClient.close();
+        mockWdmClient = null;
+        localSettingsTrait = null;
+        testCTrait = null;
+        System.out.println("testWdmClientDataSinkSetClearFlushData Test Succeeded");
+    }
+
+    void testWdmClientDataSinkRefreshGetDataRefreshClear(WeaveDeviceManager deviceMgr)
     {
         WdmClientFactory wdmClientFactory = new WdmClientFactory();
         WdmClient mockWdmClient = wdmClientFactory.create(deviceMgr);
@@ -229,11 +353,13 @@
         testCTraitVersion = testCTrait.getVersion();
         System.out.println("testCTrait GetVersion " + testCTraitVersion);
 
+        testCTrait.clear();
+
         mockWdmClient.close();
         mockWdmClient = null;
         localSettingsTrait = null;
         testCTrait = null;
-        System.out.println("testWdmClientDataSinkRefreshGetDataRefresh Test Succeeded");
+        System.out.println("testWdmClientDataSinkRefreshGetDataRefreshClear Test Succeeded");
     }
 
     void testWdmClientDataSinkRefreshIndividualGetDataRefresh(WeaveDeviceManager deviceMgr)
@@ -344,6 +470,80 @@
         System.out.println("testWdmClientDataSinkSetFlushRefreshGetData Succeeded");
     }
 
+    void testWdmClientDataSinkSetFlushEmptyStringRefreshGetData(WeaveDeviceManager deviceMgr)
+    {
+        WdmClientFactory wdmClientFactory = new WdmClientFactory();
+        WdmClient mockWdmClient = wdmClientFactory.create(deviceMgr);
+        mockWdmClient.setCompletionHandler(this);
+
+        BigInteger self_node_id = new BigInteger("-2");
+        mockWdmClient.setNodeId(self_node_id);
+
+        GenericTraitUpdatableDataSink localSettingsTrait;
+        GenericTraitUpdatableDataSink localCapabilitiesTrait;
+        GenericTraitUpdatableDataSink testCTrait;
+
+        ResourceIdentifier resourceIdentifier = new ResourceIdentifier();
+        localSettingsTrait = mockWdmClient.newDataSink(resourceIdentifier, 20, 0, "/");
+        localCapabilitiesTrait = mockWdmClient.newDataSink(resourceIdentifier, 21, 0, "/");
+        testCTrait = mockWdmClient.newDataSink(resourceIdentifier, 593165827, 0, "/");
+
+        localSettingsTrait.setCompletionHandler(this);
+        localCapabilitiesTrait.setCompletionHandler(this);
+        testCTrait.setCompletionHandler(this);
+
+        localSettingsTrait.set("/1", "");
+
+        String[] arr = new String[2];
+        arr[0] = "";
+        arr[1] = "";
+        localCapabilitiesTrait.set("/2", arr);
+
+        testCTrait.set("/1", false);
+        testCTrait.setSigned("/2", 15);
+        testCTrait.setUnsigned("/3/1", -5);
+        testCTrait.set("/3/2", false);
+        testCTrait.setUnsigned("/4", -5);
+
+        TestResult = null;
+        mockWdmClient.beginFlushUpdate();
+        ExpectSuccess("FlushUpdate");
+        System.out.println("FlushUpdate Test Succeeded");
+
+        TestResult = null;
+        mockWdmClient.beginRefreshData();
+        ExpectSuccess("RefreshData");
+        System.out.println("RefreshData Test Succeeded");
+
+        String localeProperty = localSettingsTrait.getString("/1");
+        System.out.println("GetString " + localeProperty);
+
+        String[] localeCapabilitiesArray= localCapabilitiesTrait.getStringArray("/2");
+        System.out.println("GetStringArray " + Arrays.toString(localeCapabilitiesArray));
+
+        boolean tca = testCTrait.getBoolean("/1");
+        System.out.println("GetBoolean " + tca);
+
+        int tcb = testCTrait.getInt("/2");
+        System.out.println("getInt " + tcb);
+
+        int tcc_sca = testCTrait.getInt("/3/1");
+        System.out.println("GetUnsigned" + tcc_sca);
+
+        boolean tcc_scb = testCTrait.getBoolean("/3/2");
+        System.out.println("GetBoolean " + tcc_scb);
+
+        int tcd = testCTrait.getInt("/4");
+        System.out.println("GetUnsigned " + tcd);
+
+        mockWdmClient.close();
+        mockWdmClient = null;
+        localSettingsTrait = null;
+        testCTrait = null;
+
+        System.out.println("testWdmClientDataSinkSetFlushEmptyStringRefreshGetData Succeeded");
+    }
+
     void testWdmClientDataSinkSetFlushRefreshGetBigInteger(WeaveDeviceManager deviceMgr)
     {
         WdmClientFactory wdmClientFactory = new WdmClientFactory();
@@ -656,18 +856,23 @@
     void RunMockWdmClientTest(WeaveDeviceManager deviceMgr)
     {
         System.out.println("Run Weave Data Management Start");
-
         testWdmClientCreateClose(deviceMgr);
         testWdmClientDataSinkCreateClose(deviceMgr);
+        testWdmClientDataSinkEmptyFlushData(deviceMgr);
         testWdmClientDataSinkSetFlushData(deviceMgr);
-        testWdmClientDataSinkRefreshGetDataRefresh(deviceMgr);
+        testWdmClientDataSinkSetFlushInvalidData(deviceMgr);
+        testWdmClientDataSinkSetFlushDataDeleteData(deviceMgr);
+        testWdmClientDataSinkSetClearFlushData(deviceMgr);
+        testWdmClientDataSinkRefreshGetDataRefreshClear(deviceMgr);
         testWdmClientDataSinkRefreshIndividualGetDataRefresh(deviceMgr);
         testWdmClientDataSinkSetFlushRefreshGetData(deviceMgr);
+        testWdmClientDataSinkSetFlushEmptyStringRefreshGetData(deviceMgr);
         testWdmClientDataSinkSetFlushRefreshGetBigInteger(deviceMgr);
         testWdmClientDataSinkSetBigIntegerFlushRefreshGetBigInteger(deviceMgr);
         testWdmClientDataSinkSetRefreshFlushGetData(deviceMgr);
         testWdmClientDataSinkResourceIdentifierMakeResTypeIDInt(deviceMgr);
         testWdmClientDataSinkResourceIdentifierMakeResTypeIdBytes(deviceMgr);
+
         System.out.println("Run Weave Data Management Complete");
     }
 
@@ -1156,8 +1361,30 @@
     {
     }
 
-    public void onFlushUpdateComplete()
+    public void onFlushUpdateComplete(Throwable[] exceptions, WdmClient wdmClient)
     {
+        if (exceptions != null)
+        {
+            for (int i = 0; i < exceptions.length; i++)
+            {
+                System.out.println(exceptions[i].toString());
+
+                if (exceptions[i] instanceof WdmClientFlushUpdateException)
+                {
+                    GenericTraitUpdatableDataSink dataSink =  ((WdmClientFlushUpdateException)exceptions[i]).getDataSink(wdmClient);
+                    System.out.println(((WdmClientFlushUpdateDeviceException)exceptions[i]).path);
+                    System.out.println(((WdmClientFlushUpdateDeviceException)exceptions[i]).StatusCode);
+                    dataSink.deleteData(((WdmClientFlushUpdateException)exceptions[i]).path);
+                }
+                else if (exceptions[i] instanceof WdmClientFlushUpdateDeviceException)
+                {
+                    GenericTraitUpdatableDataSink dataSink =  ((WdmClientFlushUpdateDeviceException)exceptions[i]).getDataSink(wdmClient);
+                    System.out.println(((WdmClientFlushUpdateDeviceException)exceptions[i]).path);
+                    System.out.println(((WdmClientFlushUpdateDeviceException)exceptions[i]).StatusCode);
+                    dataSink.deleteData(((WdmClientFlushUpdateDeviceException)exceptions[i]).path);
+                }
+            }
+        }
         System.out.println("    Flush Update complete");
         TestResult = "Success";
     }
diff --git a/src/device-manager/python/WeaveDeviceManager-ScriptBinding.cpp b/src/device-manager/python/WeaveDeviceManager-ScriptBinding.cpp
index e99f946..433d1b4 100644
--- a/src/device-manager/python/WeaveDeviceManager-ScriptBinding.cpp
+++ b/src/device-manager/python/WeaveDeviceManager-ScriptBinding.cpp
@@ -267,7 +267,7 @@
     NL_DLL_EXPORT WEAVE_ERROR nl_Weave_WdmClient_DeleteWdmClient(WdmClient *wdmClient);
     NL_DLL_EXPORT void nl_Weave_WdmClient_SetNodeId(WdmClient *wdmClient, uint64_t aNodeId);
     NL_DLL_EXPORT WEAVE_ERROR nl_Weave_WdmClient_NewDataSink(WdmClient *wdmClient, const ResourceIdentifier *resourceIdentifier, uint32_t aProfileId, uint64_t aInstanceId, const char * apPath, GenericTraitUpdatableDataSink ** outGenericTraitUpdatableDataSink);
-    NL_DLL_EXPORT WEAVE_ERROR nl_Weave_WdmClient_FlushUpdate(WdmClient *wdmClient, DMCompleteFunct onComplete, DMErrorFunct onError);
+    NL_DLL_EXPORT WEAVE_ERROR nl_Weave_WdmClient_FlushUpdate(WdmClient *wdmClient, DMFlushUpdateCompleteFunct onComplete, DMErrorFunct onError);
     NL_DLL_EXPORT WEAVE_ERROR nl_Weave_WdmClient_RefreshData(WdmClient *wdmClient, DMCompleteFunct onComplete, DMErrorFunct onError);
 
     NL_DLL_EXPORT WEAVE_ERROR nl_Weave_GenericTraitUpdatableDataSink_Clear(GenericTraitUpdatableDataSink * apGenericTraitUpdatableDataSink);
@@ -275,6 +275,7 @@
     NL_DLL_EXPORT WEAVE_ERROR nl_Weave_GenericTraitUpdatableDataSink_SetTLVBytes(GenericTraitUpdatableDataSink * apGenericTraitUpdatableDataSink, const char * apPath, const uint8_t * dataBuf, size_t dataLen, bool aIsConditional);
     NL_DLL_EXPORT WEAVE_ERROR nl_Weave_GenericTraitUpdatableDataSink_GetTLVBytes(GenericTraitUpdatableDataSink * apGenericTraitUpdatableDataSink, const char * apPath, ConstructBytesArrayFunct aCallback);
     NL_DLL_EXPORT uint64_t nl_Weave_GenericTraitUpdatableDataSink_GetVersion(GenericTraitUpdatableDataSink * apGenericTraitUpdatableDataSink);
+    NL_DLL_EXPORT WEAVE_ERROR nl_Weave_GenericTraitUpdatableDataSink_DeleteData(GenericTraitUpdatableDataSink * apGenericTraitUpdatableDataSink, const char * apPath);
 #endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
 }
 
@@ -1424,7 +1425,7 @@
     return err;
 }
 
-WEAVE_ERROR nl_Weave_WdmClient_FlushUpdate(WdmClient *wdmClient, DMCompleteFunct onComplete, DMErrorFunct onError)
+WEAVE_ERROR nl_Weave_WdmClient_FlushUpdate(WdmClient *wdmClient, DMFlushUpdateCompleteFunct onComplete, DMErrorFunct onError)
 {
     WEAVE_ERROR err = WEAVE_NO_ERROR;
     err = wdmClient->FlushUpdate(NULL, onComplete, onError);
@@ -1484,6 +1485,11 @@
     return version;
 }
 
+WEAVE_ERROR nl_Weave_GenericTraitUpdatableDataSink_DeleteData(GenericTraitUpdatableDataSink * apGenericTraitUpdatableDataSink, const char * apPath)
+{
+    return apGenericTraitUpdatableDataSink->DeleteData(apPath);
+}
+
 namespace nl {
 namespace Weave {
 namespace Profiles {
diff --git a/src/device-manager/python/openweave/GenericTraitUpdatableDataSink.py b/src/device-manager/python/openweave/GenericTraitUpdatableDataSink.py
index 94a8a6d..93b2af8 100644
--- a/src/device-manager/python/openweave/GenericTraitUpdatableDataSink.py
+++ b/src/device-manager/python/openweave/GenericTraitUpdatableDataSink.py
@@ -35,7 +35,11 @@
 _ConstructBytesArrayFunct                   = CFUNCTYPE(None, c_void_p, c_uint32)
 
 class GenericTraitUpdatableDataSink:
-    def __init__(self, traitInstance, wdmClient):
+    def __init__(self, resourceIdentifier, profileId, instanceId, path, traitInstance, wdmClient):
+        self._resourceIdentifier = resourceIdentifier
+        self._profileId = profileId
+        self._instanceId = instanceId
+        self._path = path
         self._traitInstance = traitInstance
         self._wdmClient = wdmClient
         self._weaveStack = WeaveStack()
@@ -47,6 +51,22 @@
         self._weaveStack = None
         self._generictraitupdatabledatasinkLib = None
 
+    @property
+    def resourceIdentifier(self):
+        return self._resourceIdentifier
+
+    @property
+    def profileId(self):
+        return self._profileId
+
+    @property
+    def instanceId(self):
+        return self._instanceId
+
+    @property
+    def path(self):
+        return self._path
+
     def close(self):
         if self._wdmClient != None:
             self._wdmClient.removeDataSinkRef(self._traitInstance)
@@ -70,9 +90,7 @@
 
     def refreshData(self):
         self._ensureNotClosed()
-        self._weaveStack.CallAsync(
-            lambda: self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_RefreshData(self._traitInstance, self._weaveStack.cbHandleComplete, self._weaveStack.cbHandleError)
-        )
+        self._weaveStack.CallAsync(lambda: self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_RefreshData(self._traitInstance, self._weaveStack.cbHandleComplete, self._weaveStack.cbHandleError))
 
     def setData(self, path, val, isConditional=False):
         self._ensureNotClosed()
@@ -115,10 +133,16 @@
             )
 
     def getVersion(self):
-        if self._traitInstance != None:
-            return self._weaveStack.Call(
-                lambda: self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_GetVersion(self._traitInstance)
-            )
+        self._ensureNotClosed()
+        return self._weaveStack.Call(
+            lambda: self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_GetVersion(self._traitInstance)
+        )
+
+    def deleteData(self, path):
+        self._ensureNotClosed()
+        return self._weaveStack.Call(
+            lambda: self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_DeleteData(self._traitInstance, path)
+        )
 
     def _ensureNotClosed(self):
         if self._traitInstance == None:
@@ -137,4 +161,6 @@
             self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_GetTLVBytes.argtypes = [ c_void_p, c_char_p, _ConstructBytesArrayFunct ]
             self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_GetTLVBytes.restype = c_uint32
             self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_GetVersion.argtypes = [ c_void_p ]
-            self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_GetVersion.restype = c_uint64
\ No newline at end of file
+            self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_GetVersion.restype = c_uint64
+            self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_DeleteData.argtypes = [ c_void_p, c_char_p ]
+            self._generictraitupdatabledatasinkLib.nl_Weave_GenericTraitUpdatableDataSink_DeleteData.restype = c_uint32
diff --git a/src/device-manager/python/openweave/WdmClient.py b/src/device-manager/python/openweave/WdmClient.py
index 00c576c..31be50b 100644
--- a/src/device-manager/python/openweave/WdmClient.py
+++ b/src/device-manager/python/openweave/WdmClient.py
@@ -26,11 +26,42 @@
 from .WeaveStack import *
 from .GenericTraitUpdatableDataSink import *
 from .ResourceIdentifier import *
+from .WeaveUtility import WeaveUtility
 
-__all__ = [ 'WdmClient' ]
+__all__ = [ 'WdmClient', 'WdmFlushUpdateStatusStruct', 'WdmClientFlushUpdateError', 'WdmClientFlushUpdateDeviceError' ]
+
+WEAVE_ERROR_STATUS_REPORT = 4044
+
+class WdmFlushUpdateStatusStruct(Structure):
+    _fields_ = [
+        ("errorCode",       c_uint32),
+        ("DeviceStatus",    DeviceStatusStruct),
+        ("path",            c_void_p),
+        ("pathLen",         c_uint32),
+        ("dataSink",        c_void_p),
+    ]
+
+class WdmClientFlushUpdateError(WeaveStackError):
+    def __init__(self, err, path, dataSink, msg=None):
+        super(WdmClientFlushUpdateError, self).__init__(err, msg)
+        self.path = path
+        self.dataSink = dataSink
+
+    def __str__(self):
+        return "WdmClientFlushUpdateError path:{}, trait profileId:{}, trait InstanceId:{}, msg:{} ".format(self.path, self.dataSink.profileId, self.dataSink.instanceId, self.msg)
+
+class WdmClientFlushUpdateDeviceError(DeviceError):
+    def __init__(self, profileId, statusCode, systemErrorCode, path, dataSink, msg=None):
+        super(WdmClientFlushUpdateDeviceError, self).__init__(profileId, statusCode, systemErrorCode, msg)
+        self.path = path
+        self.dataSink = dataSink
+
+    def __str__(self):
+        return "WdmClientFlushUpdateDeviceError path:{}, trait profileId:{}, trait InstanceId:{}, msg:{} ".format(self.path, self.dataSink.profileId, self.dataSink.instanceId, self.msg)
 
 _CompleteFunct                              = CFUNCTYPE(None, c_void_p, c_void_p)
 _ErrorFunct                                 = CFUNCTYPE(None, c_void_p, c_void_p, c_ulong, POINTER(DeviceStatusStruct))
+_FlushUpdateCompleteFunct                   = CFUNCTYPE(None, c_void_p, c_void_p, c_uint16, POINTER(WdmFlushUpdateStatusStruct))
 
 class WdmClient():
     def __init__(self):
@@ -83,9 +114,10 @@
         if (res != 0):
             raise self._weaveStack.ErrorToException(res)
 
-        addr = id(traitInstance)
+        addr = traitInstance.value
+
         if addr not in self._traitTable.keys():
-            self._traitTable[addr] = GenericTraitUpdatableDataSink(traitInstance, self)
+            self._traitTable[addr] = GenericTraitUpdatableDataSink(resourceIdentifier, profileId, instanceId, path, traitInstance, self)
 
         return self._traitTable[addr]
 
@@ -97,14 +129,36 @@
     def flushUpdate(self):
         self._ensureNotClosed()
 
-        self._weaveStack.CallAsync(
-            lambda: self._datamanagmentLib.nl_Weave_WdmClient_FlushUpdate(self._wdmClientPtr, self._weaveStack.cbHandleComplete, self._weaveStack.cbHandleError)
+        def HandleFlushUpdateComplete(appState, reqState, pathCount, statusResultsPtr):
+            statusResults = []
+            for i in range(pathCount):
+                path = WeaveUtility.VoidPtrToByteArray(statusResultsPtr[i].path, statusResultsPtr[i].pathLen).decode()
+                addr = statusResultsPtr[i].dataSink
+                if addr in self._traitTable.keys():
+                    dataSink = self._traitTable[addr]
+                else:
+                    print("unexpected, trait %d does not exist in traitTable", i)
+                    dataSink = None
+
+                if statusResultsPtr[i].errorCode == WEAVE_ERROR_STATUS_REPORT:
+                    statusResults.append(WdmClientFlushUpdateDeviceError(statusResultsPtr[i].DeviceStatus.ProfileId, statusResultsPtr[i].DeviceStatus.StatusCode, statusResultsPtr[i].DeviceStatus.SysErrorCode, path, dataSink))
+                else:
+                    statusResults.append(WdmClientFlushUpdateError(statusResultsPtr[i].errorCode, path, dataSink))
+                print(statusResults[-1])
+
+            self._weaveStack.callbackRes = statusResults
+            self._weaveStack.completeEvent.set()
+
+        cbHandleComplete = _FlushUpdateCompleteFunct(HandleFlushUpdateComplete)
+
+        return self._weaveStack.CallAsync(
+            lambda: self._datamanagmentLib.nl_Weave_WdmClient_FlushUpdate(self._wdmClientPtr, cbHandleComplete, self._weaveStack.cbHandleError)
         )
 
     def refreshData(self):
         self._ensureNotClosed()
 
-        self._weaveStack.CallAsync(
+        return self._weaveStack.CallAsync(
             lambda: self._datamanagmentLib.nl_Weave_WdmClient_RefreshData(self._wdmClientPtr, self._weaveStack.cbHandleComplete, self._weaveStack.cbHandleError)
         )
 
@@ -135,7 +189,7 @@
             self._datamanagmentLib.nl_Weave_WdmClient_NewDataSink.argtypes = [ c_void_p, POINTER(ResourceIdentifierStruct), c_uint32, c_uint64, c_char_p, c_void_p ]
             self._datamanagmentLib.nl_Weave_WdmClient_NewDataSink.restype = c_uint32
 
-            self._datamanagmentLib.nl_Weave_WdmClient_FlushUpdate.argtypes = [ c_void_p, _CompleteFunct, _ErrorFunct ]
+            self._datamanagmentLib.nl_Weave_WdmClient_FlushUpdate.argtypes = [ c_void_p, _FlushUpdateCompleteFunct, _ErrorFunct ]
             self._datamanagmentLib.nl_Weave_WdmClient_FlushUpdate.restype = c_uint32
 
             self._datamanagmentLib.nl_Weave_WdmClient_RefreshData.argtypes = [ c_void_p, _CompleteFunct, _ErrorFunct ]
diff --git a/src/device-manager/python/openweave/WeaveStack.py b/src/device-manager/python/openweave/WeaveStack.py
index bcde98f..03498c2 100644
--- a/src/device-manager/python/openweave/WeaveStack.py
+++ b/src/device-manager/python/openweave/WeaveStack.py
@@ -41,7 +41,7 @@
 from ctypes import *
 from .WeaveUtility import WeaveUtility
 
-__all__ = [ 'DeviceStatusStruct', 'WeaveStackException', 'DeviceError', 'WeaveStackError', 'WeaveStack' ]
+__all__ = [ 'DeviceStatusStruct', 'WeaveStackException', 'DeviceError', 'WeaveStackError', 'WeaveStack']
 
 WeaveStackDLLBaseName = '_WeaveDeviceMgr.so'
 
@@ -83,13 +83,14 @@
         self.systemErrorCode = systemErrorCode
         if (msg == None):
             if (systemErrorCode):
-                return "[ %08X:%d ] (system err %d)" % (profileId, statusCode, systemErrorCode)
+                self.msg = "[ %08X:%d ] (system err %d)" % (profileId, statusCode, systemErrorCode)
             else:
-                return "[ %08X:%d ]" % (profileId, statusCode)
-        self.message = msg
+                self.msg = "[ %08X:%d ]" % (profileId, statusCode)
+        else:
+            self.msg = msg
 
     def __str__(self):
-        return "Device Error: " + self.message
+        return "Device Error: " + self.msg
 
 class LogCategory(object):
     '''Debug logging categories used by openweave.'''
diff --git a/src/lib/core/WeaveTLVDebug.cpp b/src/lib/core/WeaveTLVDebug.cpp
index b5c1210..bd66a7d 100644
--- a/src/lib/core/WeaveTLVDebug.cpp
+++ b/src/lib/core/WeaveTLVDebug.cpp
@@ -140,14 +140,20 @@
             break;
 
         case kTLVType_UTF8String:
-            err = temp.GetDataPtr(strbuf);
-            VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_UTF8String"));
+            if (len > 0)
+            {
+                err = temp.GetDataPtr(strbuf);
+                VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_UTF8String"));
+            }
             aWriter("\"%-.*s\"", static_cast<int>(len), strbuf);
             break;
 
         case kTLVType_ByteString:
-            err = temp.GetDataPtr(strbuf);
-            VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_ByteString"));
+            if (len > 0)
+            {
+                err = temp.GetDataPtr(strbuf);
+                VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_ByteString"));
+            }
             aWriter("%p\n", strbuf);
             break;
 
diff --git a/src/lib/profiles/data-management/Current/SubscriptionClient.cpp b/src/lib/profiles/data-management/Current/SubscriptionClient.cpp
index 99942a3..1867ee3 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionClient.cpp
+++ b/src/lib/profiles/data-management/Current/SubscriptionClient.cpp
@@ -2915,6 +2915,36 @@
     return err;
 }
 
+WEAVE_ERROR SubscriptionClient::ClearUpdated(TraitUpdatableDataSink * aDataSink, PropertyPathHandle aPropertyHandle)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+    TraitDataHandle dataHandle;
+    const TraitSchemaEngine * schemaEngine;
+    bool needToSetUpdateRequiredVersion = false;
+    bool isTraitInstanceInUpdate = false;
+
+    LockUpdateMutex();
+
+    schemaEngine = aDataSink->GetSchemaEngine();
+
+    err = mDataSinkCatalog->Locate(aDataSink, dataHandle);
+    SuccessOrExit(err);
+
+    isTraitInstanceInUpdate = mPendingUpdateSet.IsTraitPresent(dataHandle);
+
+    if (!isTraitInstanceInUpdate)
+    {
+        WeaveLogDetail(DataManagement, "trait %d is not in update pending set, skip ClearUpdated", dataHandle);
+        goto exit;
+    }
+
+    mPendingUpdateSet.RemoveItem(TraitPath(dataHandle, aPropertyHandle));
+
+exit:
+    UnlockUpdateMutex();
+    return err;
+}
+
 /**
  * Tells the SubscriptionClient to empty the set of TraitPaths pending to be updated and abort the
  * update request that is in progress, if any.
diff --git a/src/lib/profiles/data-management/Current/SubscriptionClient.h b/src/lib/profiles/data-management/Current/SubscriptionClient.h
index c718532..5e3b492 100644
--- a/src/lib/profiles/data-management/Current/SubscriptionClient.h
+++ b/src/lib/profiles/data-management/Current/SubscriptionClient.h
@@ -390,6 +390,7 @@
     WEAVE_ERROR FlushUpdate();
     WEAVE_ERROR FlushUpdate(bool aForce);
     WEAVE_ERROR SetUpdated(TraitUpdatableDataSink * aDataSink, PropertyPathHandle aPropertyHandle, bool aIsConditional);
+    WEAVE_ERROR ClearUpdated(TraitUpdatableDataSink * aDataSink, PropertyPathHandle aPropertyHandle);
     void DiscardUpdates();
     void SuspendUpdateRetries();
     void OnCatalogChanged();
diff --git a/src/lib/profiles/data-management/Current/TraitData.cpp b/src/lib/profiles/data-management/Current/TraitData.cpp
index 121e57e..cee5325 100644
--- a/src/lib/profiles/data-management/Current/TraitData.cpp
+++ b/src/lib/profiles/data-management/Current/TraitData.cpp
@@ -37,6 +37,9 @@
 #include <Weave/Profiles/data-management/DataManagement.h>
 #include <Weave/Support/WeaveFaultInjection.h>
 #include <Weave/Support/RandUtils.h>
+#if WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+#include <string>
+#endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
 
 using namespace ::nl::Weave;
 using namespace ::nl::Weave::TLV;
@@ -239,6 +242,41 @@
     return WEAVE_NO_ERROR;
 }
 
+#if WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+WEAVE_ERROR TraitSchemaEngine::MapHandleToPath(PropertyPathHandle aHandle, std::string & aPathString) const
+{
+    // Use the tree depth specified by the schema to correctly size our path walk store
+    PropertyPathHandle pathWalkStore[mSchema.mTreeDepth];
+    uint32_t pathWalkDepth         = 0;
+    WEAVE_ERROR err                = WEAVE_NO_ERROR;
+    PropertyPathHandle curProperty = aHandle;
+
+    // Walk up the path till root and keep track of the handles encountered along the way.
+    while (curProperty != kRootPropertyPathHandle)
+    {
+        pathWalkStore[pathWalkDepth++] = curProperty;
+        curProperty                    = GetParent(curProperty);
+    }
+
+    // Write it into std string by reverse walking over the encountered handles starting from root, split tags with /
+    while (pathWalkDepth)
+    {
+        PropertyPathHandle curHandle = pathWalkStore[pathWalkDepth - 1];
+
+        if (pathWalkDepth > 0)
+        {
+            aPathString.append("/");
+        }
+        aPathString.append(std::to_string((uint8_t)GetTag(curHandle)));
+
+        pathWalkDepth--;
+    }
+
+exit:
+    return WEAVE_NO_ERROR;
+}
+#endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+
 uint64_t TraitSchemaEngine::GetTag(PropertyPathHandle aHandle) const
 {
     if (IsDictionary(GetParent(aHandle)))
@@ -1500,6 +1538,19 @@
 exit:
     return err;
 }
+
+WEAVE_ERROR TraitUpdatableDataSink::ClearUpdated(SubscriptionClient * apSubClient, PropertyPathHandle aPropertyHandle)
+{
+    WEAVE_ERROR err = WEAVE_NO_ERROR;
+
+    VerifyOrExit(aPropertyHandle != kNullPropertyPathHandle, err = WEAVE_ERROR_INVALID_ARGUMENT);
+
+    err = apSubClient->ClearUpdated(this, aPropertyHandle);
+
+exit:
+    return err;
+}
+
 #endif // WEAVE_CONFIG_ENABLE_WDM_UPDATE
 
 #if WDM_ENABLE_PUBLISHER_UPDATE_SERVER_SUPPORT
diff --git a/src/lib/profiles/data-management/Current/TraitData.h b/src/lib/profiles/data-management/Current/TraitData.h
index c421033..41454d1 100644
--- a/src/lib/profiles/data-management/Current/TraitData.h
+++ b/src/lib/profiles/data-management/Current/TraitData.h
@@ -36,6 +36,10 @@
 #include <Weave/Support/CodeUtils.h>
 #include <Weave/Profiles/data-management/MessageDef.h>
 
+#if WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+#include <string>
+#endif // WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+
 namespace nl {
 namespace Weave {
 namespace Profiles {
@@ -357,6 +361,16 @@
      */
     WEAVE_ERROR MapHandleToPath(PropertyPathHandle aHandle, nl::Weave::TLV::TLVWriter & aPathWriter) const;
 
+#if WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+    /**
+     * Convert the path handle to a std string path
+     *
+     * @retval #WEAVE_NO_ERROR On success.
+     * @retval other           Was unable to convert the handle to a std string path
+     */
+    WEAVE_ERROR MapHandleToPath(PropertyPathHandle aHandle, std::string & aPathString) const;
+#endif //WEAVE_CONFIG_DATA_MANAGEMENT_CLIENT_EXPERIMENTAL
+
     /**
      * Given a path handle and a reader positioned on the corresponding data element, process the data buffer pointed to by the
      * reader and store it into the sink by invoking the SetLeafData call whenever a leaf data item is encountered.
@@ -793,6 +807,7 @@
                                 bool & aIsNull, bool & aIsPresent) __OVERRIDE;
 
     WEAVE_ERROR SetUpdated(SubscriptionClient * apSubClient, PropertyPathHandle aPropertyHandle, bool aIsConditional = false);
+    WEAVE_ERROR ClearUpdated(SubscriptionClient * apSubClient, PropertyPathHandle aPropertyHandle);
 
     void Lock(SubscriptionClient * apSubClient);
     void Unlock(SubscriptionClient * apSubClient);
diff --git a/src/lib/profiles/data-management/Current/TraitPathStore.cpp b/src/lib/profiles/data-management/Current/TraitPathStore.cpp
index 697d602..240891b 100644
--- a/src/lib/profiles/data-management/Current/TraitPathStore.cpp
+++ b/src/lib/profiles/data-management/Current/TraitPathStore.cpp
@@ -254,6 +254,22 @@
     }
 }
 
+void TraitPathStore::RemoveItem(const TraitPath &aItem)
+{
+    for (size_t i = GetFirstValidItem(aItem.mTraitDataHandle);
+         i < GetPathStoreSize();
+         i = GetNextValidItem(i, aItem.mTraitDataHandle))
+    {
+        if (mStore[i].mTraitPath.mPropertyPathHandle == aItem.mPropertyPathHandle)
+        {
+            RemoveItemAt(i);
+            WeaveLogDetail(DataManagement, "Removing item %u t%u p%u", i,
+                           mStore[i].mTraitPath.mTraitDataHandle,
+                           mStore[i].mTraitPath.mPropertyPathHandle);
+        }
+    }
+}
+
 void TraitPathStore::RemoveItemAt(size_t aIndex)
 {
     VerifyOrDie(mNumItems > 0);
diff --git a/src/lib/profiles/data-management/Current/TraitPathStore.h b/src/lib/profiles/data-management/Current/TraitPathStore.h
index 574550d..df61ea4 100644
--- a/src/lib/profiles/data-management/Current/TraitPathStore.h
+++ b/src/lib/profiles/data-management/Current/TraitPathStore.h
@@ -81,6 +81,7 @@
         size_t GetNextValidItem(size_t i, TraitDataHandle aTraitDataHandle) const;
 
         void RemoveTrait(TraitDataHandle aDataHandle);
+        void RemoveItem(const TraitPath &aItem);
         void RemoveItemAt(size_t aIndex);
 
         void Compact();
diff --git a/src/test-apps/MockSourceTraits.cpp b/src/test-apps/MockSourceTraits.cpp
index 9c88e35..2994a42 100644
--- a/src/test-apps/MockSourceTraits.cpp
+++ b/src/test-apps/MockSourceTraits.cpp
@@ -166,6 +166,7 @@
     memcpy(mLocales[0], "pl-PL", MAX_LOCALE_SIZE);
     memcpy(mLocales[1], "ja-JP", MAX_LOCALE_SIZE);
     memcpy(mLocales[2], "fr-FR", MAX_LOCALE_SIZE);
+    mNumLocales = 3;
 }
 
 void LocaleCapabilitiesTraitDataSource::Mutate()
diff --git a/src/test-apps/happy/lib/WeaveDeviceManager.py b/src/test-apps/happy/lib/WeaveDeviceManager.py
index 79e25f9..d4ad893 100644
--- a/src/test-apps/happy/lib/WeaveDeviceManager.py
+++ b/src/test-apps/happy/lib/WeaveDeviceManager.py
@@ -2,7 +2,7 @@
 
 #
 #    Copyright (c) 2017-2018 Nest Labs, Inc.
-#    Copyright (c) 2019 Google, LLC.
+#    Copyright (c) 2019-2020 Google, LLC.
 #    All rights reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License");
@@ -152,12 +152,11 @@
         except WeaveStack.WeaveStackException, ex:
             print str(ex)
             return
-
         print "close wdm client complete"
 
-    def newDataSink(self, profileid, instanceid, path, testResOption="default"):
+    def newDataSink(self, statusProfileId, instanceid, path, testResOption="default"):
         """
-          new-data-sink <profileid, instanceid, path>
+          new-data-sink <statusProfileId, instanceid, path>
         """
         if self.wdmClient == None:
             print "wdmclient not initialized"
@@ -171,7 +170,7 @@
             resourceIdentifier = ResourceIdentifier.ResourceIdentifier.MakeResTypeIdBytes(0, b'\xfe\xff\xff\xff\xff\xff\xff\xff')
 
         try:
-            traitInstance = self.wdmClient.newDataSink(resourceIdentifier, profileid, instanceid, path)
+            traitInstance = self.wdmClient.newDataSink(resourceIdentifier, statusProfileId, instanceid, path)
         except WeaveStack.WeaveStackException, ex:
             print str(ex)
             return
@@ -185,39 +184,38 @@
             return
 
         try:
-            self.wdmClient.flushUpdate()
+            result = self.wdmClient.flushUpdate()
+            print "flushUpdate Complete"
+            print result
+            return result
         except WeaveStack.WeaveStackException, ex:
             print str(ex)
             return
 
-        print "flush update complete"
-
     def refreshData(self):
         if self.wdmClient == None:
             print "wdmclient not initialized"
             return
 
         try:
-            self.wdmClient.refreshData()
+            result = self.wdmClient.refreshData()
+            print "refresh trait data complete"
         except WeaveStack.WeaveStackException, ex:
             print str(ex)
             return
 
-        print "refresh trait data complete"
-
     def refreshIndividualData(self, traitInstance):
         if self.wdmClient == None or traitInstance == None:
             print "wdmclient or traitInstance not initialized"
             return
 
         try:
-            traitInstance.refreshData()
+            result = traitInstance.refreshData()
+            print "refresh individual trait data complete"
         except WeaveStack.WeaveStackException, ex:
             print str(ex)
             return
 
-        print "refresh individual trait data complete"
-
     def closeIndividualTrait(self, traitInstance):
         if self.wdmClient == None or traitInstance == None:
             print "wdmclient or traitInstance not initialized"
@@ -225,12 +223,11 @@
 
         try:
             traitInstance.close()
+            print "close current trait"
         except WeaveStack.WeaveStackException, ex:
             print str(ex)
             return
 
-        print "close current trait"
-
     def setData(self, traitInstance, path, value):
         if self.wdmClient == None or traitInstance == None:
             print "wdmclient or traitInstance not initialized"
@@ -257,13 +254,12 @@
 
         try:
             val = traitInstance.getData(path)
+            print "get data in trait complete"
             print val
         except WeaveStack.WeaveStackException, ex:
             print str(ex)
             return
 
-        print "get data in trait complete"
-
     def getVersion(self, traitInstance):
         if self.wdmClient == None or traitInstance == None:
             print "wdmclient or traitInstance not initialized"
@@ -277,7 +273,27 @@
             print str(ex)
             return
 
-        print "get version in trait complete"
+    def clearTrait(self, traitInstance):
+        if self.wdmClient == None or traitInstance == None:
+            print "wdmclient or traitInstance not initialized"
+            return
+
+        try:
+            traitInstance.clear()
+        except WeaveStack.WeaveStackException, ex:
+            print str(ex)
+            return
+
+    def deleteData(self, traitInstance, path):
+        if self.wdmClient == None or traitInstance == None:
+            print "wdmclient or traitInstance not initialized"
+            return
+
+        try:
+            traitInstance.deleteData(path)
+        except WeaveStack.WeaveStackException, ex:
+            print str(ex)
+            return
 
 def testWdmClientCreateClose(testObject):
     testObject.createWdmClient()
@@ -295,7 +311,7 @@
     testObject.createWdmClient()
     localeSettingsTrait = testObject.newDataSink(20, 0, "/")
     TestCTrait = testObject.newDataSink(593165827, 0, "/")
-    testObject.flushUpdate()
+    results = testObject.flushUpdate()
     testObject.closeWdmClient()
     print "testWdmClientDataSinkEmptyFlushData completes"
 
@@ -309,10 +325,86 @@
     testObject.setData(TestCTrait, "/3/1", 16)
     testObject.setData(TestCTrait, "/3/2", False)
     testObject.setData(TestCTrait, "/4", 17)
-    testObject.flushUpdate()
+    results = testObject.flushUpdate()
     testObject.closeWdmClient()
     print "testWdmClientDataSinkSetFlushData completes"
 
+def testWdmClientDataSinkSetFlushInvalidData(testObject):
+    testObject.createWdmClient()
+    localeSettingsTrait = testObject.newDataSink(20, 0, "/")
+    TestCTrait = testObject.newDataSink(593165827, 0, "/")
+    testObject.setData(localeSettingsTrait, "/1", 0.1)
+    testObject.setData(TestCTrait, "/1", False)
+    testObject.setData(TestCTrait, "/2", 15)
+    testObject.setData(TestCTrait, "/3/1", "TESTTEST")
+    testObject.setData(TestCTrait, "/3/2", False)
+    testObject.setData(TestCTrait, "/4", 17)
+    results1 = testObject.flushUpdate()
+    if len(results1) != 2:
+        raise ValueError("testWdmClientDataSinkSetFlushInvalidData stage1  fails")
+    print "testWdmClientDataSinkSetFlushInvalidData stage1 completes"
+
+    results2 = testObject.flushUpdate()
+    if len(results2) != 0:
+        raise ValueError("testWdmClientDataSinkSetFlushInvalidData stage2  fails")
+    print "testWdmClientDataSinkSetFlushInvalidData stage2 completes"
+
+    for ele in results1:
+        print "clear trait: " + str(ele.dataSink.profileId)
+        print "clear trait path:" + str(ele.path)
+        testObject.deleteData(ele.dataSink, ele.path)
+
+    results3 = testObject.flushUpdate()
+    if len(results3) != 0:
+        raise ValueError("testWdmClientDataSinkSetFlushInvalidData stage3  fails")
+
+    testObject.setData(TestCTrait, "/4", 20)
+    results4 = testObject.flushUpdate()
+    if len(results4) != 0:
+        raise ValueError("testWdmClientDataSinkSetFlushInvalidData stage4  fails")
+
+    testObject.closeWdmClient()
+    print "testWdmClientDataSinkSetFlushInvalidData completes"
+
+def testWdmClientDataSinkSetFlushDataDeleteData(testObject):
+    testObject.createWdmClient()
+    localeSettingsTrait = testObject.newDataSink(20, 0, "/")
+    TestCTrait = testObject.newDataSink(593165827, 0, "/")
+    testObject.setData(localeSettingsTrait, "/1", "en-US")
+    testObject.setData(TestCTrait, "/1", False)
+    testObject.setData(TestCTrait, "/2", 15)
+    testObject.setData(TestCTrait, "/3/1", 16)
+    testObject.setData(TestCTrait, "/3/2", False)
+    testObject.setData(TestCTrait, "/4", 17)
+
+    testObject.deleteData(localeSettingsTrait, "/1")
+    testObject.deleteData(TestCTrait, "/1")
+    testObject.deleteData(TestCTrait, "/2")
+    testObject.deleteData(TestCTrait, "/3/1")
+    testObject.deleteData(TestCTrait, "/3/2")
+
+    results = testObject.flushUpdate()
+    testObject.closeWdmClient()
+    print "testWdmClientDataSinkSetFlushDataDeleteData completes"
+
+def testWdmClientDataSinkSetClearFlushData(testObject):
+    testObject.createWdmClient()
+    localeSettingsTrait = testObject.newDataSink(20, 0, "/")
+    TestCTrait = testObject.newDataSink(593165827, 0, "/")
+    testObject.setData(localeSettingsTrait, "/1", "en-US")
+    testObject.setData(TestCTrait, "/1", False)
+    testObject.setData(TestCTrait, "/2", 15)
+    testObject.setData(TestCTrait, "/3/1", 16)
+    testObject.setData(TestCTrait, "/3/2", False)
+    testObject.setData(TestCTrait, "/4", 17)
+
+    testObject.clearTrait(localeSettingsTrait)
+    testObject.clearTrait(TestCTrait)
+
+    results = testObject.flushUpdate()
+    testObject.closeWdmClient()
+    print "testWdmClientDataSinkSetClearFlushData completes"
+
 def testWdmClientDataSinkRefreshIndividualGetDataRefresh(testObject):
     testObject.createWdmClient()
     localeSettingsTrait = testObject.newDataSink(20, 0, "/")
@@ -335,7 +427,8 @@
     testObject.createWdmClient()
     localeSettingsTrait = testObject.newDataSink(20, 0, "/")
     TestCTrait = testObject.newDataSink(593165827, 0, "/")
-    testObject.refreshData()
+    refreshResults1 = testObject.refreshData()
+
     localeSettingsTraitVersion = testObject.getVersion(localeSettingsTrait)
     TestCTraitVersion = testObject.getVersion(TestCTrait)
     testObject.getData(localeSettingsTrait, "/1")
@@ -344,7 +437,9 @@
     testObject.getData(TestCTrait, "/3/1")
     testObject.getData(TestCTrait, "/3/2")
     testObject.getData(TestCTrait, "/4")
-    testObject.refreshData()
+
+    refreshResults2 = testObject.refreshData()
+
     localeSettingsTraitVersion = testObject.getVersion(localeSettingsTrait)
     TestCTraitVersion = testObject.getVersion(TestCTrait)
     testObject.closeWdmClient()
@@ -354,9 +449,9 @@
     testObject.createWdmClient()
     localeSettingsTrait = testObject.newDataSink(20, 0, "/")
     TestCTrait = testObject.newDataSink(593165827, 0, "/")
-    testObject.refreshIndividualData(localeSettingsTrait)
+    refreshResults1 = testObject.refreshIndividualData(localeSettingsTrait)
     testObject.closeIndividualTrait(localeSettingsTrait)
-    testObject.refreshIndividualData(TestCTrait)
+    refreshResults2 = testObject.refreshIndividualData(TestCTrait)
     testObject.closeIndividualTrait(TestCTrait)
     testObject.closeWdmClient()
     print "testWdmClientDataSinkCloseIndividualData completes"
@@ -456,6 +551,9 @@
     testWdmClientDataSinkEmptyFlushData(testObject)
     testWdmClientDataSinkCreateClose(testObject)
     testWdmClientDataSinkSetFlushData(testObject)
+    testWdmClientDataSinkSetFlushInvalidData(testObject)
+    testWdmClientDataSinkSetFlushDataDeleteData(testObject)
+    testWdmClientDataSinkSetClearFlushData(testObject)
     testWdmClientDataSinkSetFlushRefreshGetData(testObject)
     testWdmClientDataSinkRefreshGetDataRefresh(testObject)
     testWdmClientDataSinkRefreshIndividualGetDataRefresh(testObject)