diff --git a/indra/llmath/llvolumemgr.cpp b/indra/llmath/llvolumemgr.cpp
index a8e9ce69f304eb10db8b2a0c08a6aae67b74bd6b..6ae782791553aa04da97c7f75834c9e6e24df677 100644
--- a/indra/llmath/llvolumemgr.cpp
+++ b/indra/llmath/llvolumemgr.cpp
@@ -89,7 +89,7 @@ BOOL LLVolumeMgr::cleanup()
 // Note however that LLVolumeLODGroup that contains the volume
 //  also holds a LLPointer so the volume will only go away after
 //  anything holding the volume and the LODGroup are destroyed
-LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 detail)
+LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32 lod)
 {
 	LLVolumeLODGroup* volgroupp;
 	if (mDataMutex)
@@ -109,7 +109,7 @@ LLVolume* LLVolumeMgr::refVolume(const LLVolumeParams &volume_params, const S32
 	{
 		mDataMutex->unlock();
 	}
-	return volgroupp->refLOD(detail);
+	return volgroupp->refLOD(lod);
 }
 
 // virtual
@@ -287,18 +287,18 @@ bool LLVolumeLODGroup::cleanupRefs()
 	return res;
 }
 
-LLVolume* LLVolumeLODGroup::refLOD(const S32 detail)
+LLVolume* LLVolumeLODGroup::refLOD(const S32 lod)
 {
-	llassert(detail >=0 && detail < NUM_LODS);
-	mAccessCount[detail]++;
+	llassert(lod >=0 && lod < NUM_LODS);
+	mAccessCount[lod]++;
 	
 	mRefs++;
-	if (mVolumeLODs[detail].isNull())
+	if (mVolumeLODs[lod].isNull())
 	{
-		mVolumeLODs[detail] = new LLVolume(mVolumeParams, mDetailScales[detail]);
+		mVolumeLODs[lod] = new LLVolume(mVolumeParams, mDetailScales[lod]);
 	}
-	mLODRefs[detail]++;
-	return mVolumeLODs[detail];
+	mLODRefs[lod]++;
+	return mVolumeLODs[lod];
 }
 
 BOOL LLVolumeLODGroup::derefLOD(LLVolume *volumep)
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index f5c2314b286d1aa072973b7a0c2f5ada6af92545..f770292465296b5eff53a7699282988ff5cf12b7 100644
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -2937,7 +2937,7 @@ S32 LLMeshRepository::getActualMeshLOD(LLMeshHeader& header, S32 lod)
 	}
 
 	//search up to find then ext available higher lod
-	for (S32 i = lod+1; i < 4; ++i)
+	for (S32 i = lod+1; i < LLVolumeLODGroup::NUM_LODS; ++i)
 	{
 		if (header.mLodSize[i] > 0)
 		{
@@ -3099,7 +3099,7 @@ void LLMeshHeaderHandler::processFailure(LLCore::HttpStatus status)
 
 	// Can't get the header so none of the LODs will be available
 	LLMutexLock lock(gMeshRepo.mThread->mMutex);
-	for (int i(0); i < 4; ++i)
+	for (int i(0); i < LLVolumeLODGroup::NUM_LODS; ++i)
 	{
 		gMeshRepo.mThread->mUnavailableQ.emplace_back(mMeshParams, i);
 	}
@@ -3128,7 +3128,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
 
 		// Can't get the header so none of the LODs will be available
 		LLMutexLock lock(gMeshRepo.mThread->mMutex);
-		for (int i(0); i < 4; ++i)
+		for (int i(0); i < LLVolumeLODGroup::NUM_LODS; ++i)
 		{
 			gMeshRepo.mThread->mUnavailableQ.emplace_back(mMeshParams, i);
 		}
@@ -3209,7 +3209,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b
 
 			// headerReceived() parsed header, but header's data is invalid so none of the LODs will be available
 			LLMutexLock lock(gMeshRepo.mThread->mMutex);
-			for (int i(0); i < 4; ++i)
+			for (int i(0); i < LLVolumeLODGroup::NUM_LODS; ++i)
 			{
 				gMeshRepo.mThread->mUnavailableQ.emplace_back(mMeshParams, i);
 			}
@@ -3584,7 +3584,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 	// Manage time-to-load metrics for mesh download operations.
 	metricsProgress(1);
 
-	if (detail < 0 || detail >= 4)
+	if (detail < 0 || detail >= LLVolumeLODGroup::NUM_LODS)
 	{
 		return detail;
 	}
@@ -3648,7 +3648,7 @@ S32 LLMeshRepository::loadMesh(LLVOVolume* vobj, const LLVolumeParams& mesh_para
 			}
 
 			//no lower LOD is a available, is a higher lod available?
-			for (S32 i = detail+1; i < 4; ++i)
+			for (S32 i = detail+1; i < LLVolumeLODGroup::NUM_LODS; ++i)
 			{
 				LLVolume* lod = group->refLOD(i);
 				if (lod && lod->isMeshAssetLoaded() && lod->getNumVolumeFaces() > 0)
@@ -4066,7 +4066,7 @@ void LLMeshRepository::notifyMeshUnavailable(const LLVolumeParams& mesh_params,
 	{
 		F32 detail = LLVolumeLODGroup::getVolumeScaleFromDetail(lod);
 
-        LLVolume* sys_volume = LLPrimitive::getVolumeManager()->refVolume(mesh_params, detail);
+        LLVolume* sys_volume = LLPrimitive::getVolumeManager()->refVolume(mesh_params, lod);
         if (sys_volume)
         {
             sys_volume->setMeshAssetUnavaliable(true);
@@ -4447,7 +4447,7 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* by
             {
                 LL_WARNS() << mesh_id << "bytes mismatch " << *bytes << " " << data.getSizeTotal() << LL_ENDL;
             }
-            if (bytes_visible && (lod >=0) && (lod < 4) && (*bytes_visible != data.getSizeByLOD(lod)))
+            if (bytes_visible && (lod >=0) && (lod < LLVolumeLODGroup::NUM_LODS) && (*bytes_visible != data.getSizeByLOD(lod)))
             {
                 LL_WARNS() << mesh_id << "bytes_visible mismatch " << *bytes_visible << " " << data.getSizeByLOD(lod) << LL_ENDL;
             }
@@ -4609,7 +4609,7 @@ bool LLMeshCostData::init(const LLMeshHeader& header)
     static LLCachedControl<U32> minimum_size(gSavedSettings, "MeshMinimumByteSize", 16); //make sure nothing is "free"
     static LLCachedControl<U32> bytes_per_triangle(gSavedSettings, "MeshBytesPerTriangle", 16);
 
-    for (S32 i=0; i<4; i++)
+    for (S32 i=0; i<LLVolumeLODGroup::NUM_LODS; i++)
     {
         mEstTrisByLOD[i] = llmax((F32)mSizeByLOD[i] - (F32)metadata_discount, (F32)minimum_size) / (F32)bytes_per_triangle;
     }
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 391d2638315005b4db7cf5d1bfac81cf1d320d50..3dcdb4bb7b05e9a895784fe1cd9affb2191bd5a2 100644
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -504,7 +504,11 @@ void LLPanelFace::sendTexture()
 		{
 			id = mTextureCtrl->getImageAssetID();
 		}
-		LLSelectMgr::getInstance()->selectionSetImage(id);
+        if (!LLSelectMgr::getInstance()->selectionSetImage(id))
+        {
+            // need to refresh value in texture ctrl
+            refresh();
+        }
 	}
 }
 
@@ -2939,7 +2943,11 @@ void LLPanelFace::onCommitPbr(const LLSD& data)
         {
             id = pbr_ctrl->getImageAssetID();
         }
-        LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id);
+        if (!LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
+        {
+            // If failed to set material, refresh pbr_ctrl's value
+            refresh();
+        }
     }
 }
 
@@ -2963,8 +2971,14 @@ void LLPanelFace::onSelectPbr(const LLSD& data)
         {
             id = pbr_ctrl->getImageAssetID();
         }
-        LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id);
-        LLSelectedTEMaterial::setMaterialID(this, id);
+        if (LLSelectMgr::getInstance()->selectionSetGLTFMaterial(id))
+        {
+            LLSelectedTEMaterial::setMaterialID(this, id);
+        }
+        else
+        {
+            refresh();
+        }
     }
 }
 
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 1bcc105217fcb7fb442b288781552298c6846bf8..7c638cd0f2603abdfa7d2bc779458dffae6b0573 100644
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -1821,7 +1821,7 @@ void LLObjectSelection::applyNoCopyPbrMaterialToTEs(LLViewerInventoryItem* item)
 // selectionSetImage()
 //-----------------------------------------------------------------------------
 // *TODO: re-arch texture applying out of lltooldraganddrop
-void LLSelectMgr::selectionSetImage(const LLUUID& imageid)
+bool LLSelectMgr::selectionSetImage(const LLUUID& imageid)
 {
 	// First for (no copy) textures and multiple object selection
 	LLViewerInventoryItem* item = gInventory.getItem(imageid);
@@ -1829,9 +1829,11 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid)
 		&& !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
 		&& (mSelectedObjects->getNumNodes() > 1) )
 	{
-		LL_WARNS() << "Attempted to apply no-copy texture to multiple objects"
-				<< LL_ENDL;
-		return;
+         LL_DEBUGS() << "Attempted to apply no-copy texture " << imageid
+             << " to multiple objects" << LL_ENDL;
+
+        LLNotificationsUtil::add("FailedToApplyTextureNoCopyToMultiple");
+        return false;
 	}
 
 	struct f : public LLSelectedTEFunctor
@@ -1899,12 +1901,14 @@ void LLSelectMgr::selectionSetImage(const LLUUID& imageid)
 		}
 	} sendfunc(item);
 	getSelection()->applyToObjects(&sendfunc);
+
+    return true;
 }
 
 //-----------------------------------------------------------------------------
 // selectionSetGLTFMaterial()
 //-----------------------------------------------------------------------------
-void LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
+bool LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
 {
     // First for (no copy) textures and multiple object selection
     LLViewerInventoryItem* item = gInventory.getItem(mat_id);
@@ -1912,9 +1916,11 @@ void LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
         && !item->getPermissions().allowOperationBy(PERM_COPY, gAgent.getID())
         && (mSelectedObjects->getNumNodes() > 1))
     {
-        LL_WARNS() << "Attempted to apply no-copy material to multiple objects"
-            << LL_ENDL;
-        return;
+        LL_DEBUGS() << "Attempted to apply no-copy material " << mat_id
+            << "to multiple objects" << LL_ENDL;
+
+        LLNotificationsUtil::add("FailedToApplyGLTFNoCopyToMultiple");
+        return false;
     }
 
     struct f : public LLSelectedTEFunctor
@@ -1986,6 +1992,8 @@ void LLSelectMgr::selectionSetGLTFMaterial(const LLUUID& mat_id)
     getSelection()->applyToObjects(&sendfunc);
 
     LLGLTFMaterialList::flushUpdates();
+
+    return true;
 }
 
 //-----------------------------------------------------------------------------
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index 74fbb84a96d360a225e9c9a9a4f4d9f3bd961b20..b905d54e4ebfe48ac9f2f6d1675526b63b32fdd5 100644
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -648,8 +648,8 @@ class LLSelectMgr final : public LLEditMenuHandler, public LLSimpleton<LLSelectM
 	void selectionSetDensity(F32 density);
 	void selectionSetRestitution(F32 restitution);
 	void selectionSetMaterial(U8 material);
-	void selectionSetImage(const LLUUID& imageid); // could be item or asset id
-    void selectionSetGLTFMaterial(const LLUUID& mat_id); // could be item or asset id
+	bool selectionSetImage(const LLUUID& imageid); // could be item or asset id
+    bool selectionSetGLTFMaterial(const LLUUID& mat_id); // could be item or asset id
 	void selectionSetColor(const LLColor4 &color);
 	void selectionSetColorOnly(const LLColor4 &color); // Set only the RGB channels
 	void selectionSetAlphaOnly(const F32 alpha); // Set only the alpha channel
diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp
index 8d1abbde898904f6eed8774b7156863af7ce0d2e..1ff165eee45c97eb80874565e06423b4feface46 100644
--- a/indra/newview/lltooldraganddrop.cpp
+++ b/indra/newview/lltooldraganddrop.cpp
@@ -40,6 +40,7 @@
 #include "llfloatertools.h"
 #include "llgesturemgr.h"
 #include "llgiveinventory.h"
+#include "llgltfmateriallist.h"
 #include "llhudmanager.h"
 #include "llhudeffecttrail.h"
 #include "llimview.h"
@@ -1101,12 +1102,17 @@ void LLToolDragAndDrop::dropMaterialOneFace(LLViewerObject* hit_obj,
         LL_WARNS() << "LLToolDragAndDrop::dropTextureOneFace no material item." << LL_ENDL;
         return;
     }
-    LLUUID asset_id = item->getAssetUUID();
     BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
     if (!success)
     {
         return;
     }
+    LLUUID asset_id = item->getAssetUUID();
+    if (asset_id.isNull())
+    {
+        // use blank material
+        asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID;
+    }
 
     hit_obj->setRenderMaterialID(hit_face, asset_id);
 
@@ -1127,13 +1133,19 @@ void LLToolDragAndDrop::dropMaterialAllFaces(LLViewerObject* hit_obj,
         LL_WARNS() << "LLToolDragAndDrop::dropTextureAllFaces no material item." << LL_ENDL;
         return;
     }
-    LLUUID asset_id = item->getAssetUUID();
     BOOL success = handleDropMaterialProtections(hit_obj, item, source, src_id);
     if (!success)
     {
         return;
     }
 
+    LLUUID asset_id = item->getAssetUUID();
+    if (asset_id.isNull())
+    {
+        // use blank material
+        asset_id = LLGLTFMaterialList::BLANK_MATERIAL_ASSET_ID;
+    }
+
     hit_obj->setRenderMaterialIDs(asset_id);
     dialog_refresh_all();
     // send the update to the simulator
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 8b9ab9737e2515cfc726ab891661415c09ad75df..3569ff6dd8ffbbf7839050e7fe178740e2f3feff 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -9378,6 +9378,26 @@ Paste failed. [REASON]
     yestext="OK"/>
   </notification>
 
+  <notification
+   icon="alertmodal.tga"
+   name="FailedToApplyTextureNoCopyToMultiple"
+   type="alertmodal">
+Failed to apply texture. You can not apply a no-copy texture to multiple objects.
+   <usetemplate
+    name="okbutton"
+    yestext="OK"/>
+  </notification>
+
+  <notification
+   icon="alertmodal.tga"
+   name="FailedToApplyGLTFNoCopyToMultiple"
+   type="alertmodal">
+Failed to apply GLTF material. You can not apply a no-copy material to multiple objects.
+   <usetemplate
+    name="okbutton"
+    yestext="OK"/>
+  </notification>
+
   <notification
    icon="alertmodal.tga"
    name="FacePasteTexturePermissions"