diff --git a/indra/llprimitive/llmodelloader.cpp b/indra/llprimitive/llmodelloader.cpp
index c8da68afc8f606071d5cb7ccc9e8114a6cd9759a..5171621007445bdcd06b136dcfa6fd3188991b50 100644
--- a/indra/llprimitive/llmodelloader.cpp
+++ b/indra/llprimitive/llmodelloader.cpp
@@ -127,7 +127,7 @@ LLModelLoader::LLModelLoader(
 , mStateCallback(state_cb)
 , mOpaqueData(opaque_userdata)
 , mRigValidJointUpload(true)
-, mLegacyRigValid(true)
+, mLegacyRigFlags(0)
 , mNoNormalize(false)
 , mNoOptimize(false)
 , mCacheOnlyHitIfRigged(false)
@@ -136,6 +136,7 @@ LLModelLoader::LLModelLoader(
 {    
 	assert_main_thread();
 	sActiveLoaderList.push_back(this) ;
+	mWarningsArray = LLSD::emptyArray();
 }
 
 LLModelLoader::~LLModelLoader()
@@ -146,7 +147,7 @@ LLModelLoader::~LLModelLoader()
 
 void LLModelLoader::run()
 {
-	mWarningStream.clear();
+	mWarningsArray.clear();
 	doLoadModel();
 	doOnIdleOneTime(boost::bind(&LLModelLoader::loadModelCallback,this));
 }
@@ -388,7 +389,7 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st
 	//2. It is suitable for upload as standard av with just skin weights
 	
 	bool isJointPositionUploadOK = isRigSuitableForJointPositionUpload( jointListFromAsset );
-	bool isRigLegacyOK			 = isRigLegacy( jointListFromAsset );
+	U32 legacy_rig_flags		 = determineRigLegacyFlags( jointListFromAsset );
 
 	// It's OK that both could end up being true.
 
@@ -402,19 +403,16 @@ void LLModelLoader::critiqueRigForUploadApplicability( const std::vector<std::st
 		setRigValidForJointPositionUpload( false );
 	}
 
-	if ( !isRigLegacyOK) 
-	{	
-        // This starts out true, becomes false if false for any loaded
-        // mesh. 
-		setLegacyRigValid( false );
-	}
+	legacy_rig_flags |= getLegacyRigFlags();
+	// This starts as 0, changes if any loaded mesh has issues
+	setLegacyRigFlags(legacy_rig_flags);
 
 }
 
 //-----------------------------------------------------------------------------
-// isRigLegacy()
+// determineRigLegacyFlags()
 //-----------------------------------------------------------------------------
-bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAsset )
+U32 LLModelLoader::determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset )
 {
 	//No joints in asset
 	if ( jointListFromAsset.size() == 0 )
@@ -427,8 +425,12 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs
     {
         LL_WARNS() << "Rigged to " << jointListFromAsset.size() << " joints, max is " << mMaxJointsPerMesh << LL_ENDL;
         LL_WARNS() << "Skinning disabled due to too many joints" << LL_ENDL;
-        mWarningStream << "Skinning disabled due to too many joints, maximum amount per mesh: " << mMaxJointsPerMesh << "\n";
-        return false;
+        LLSD args;
+        args["Message"] = "TooManyJoint";
+        args["[JOINTS]"] = LLSD::Integer(jointListFromAsset.size());
+        args["[MAX]"] = LLSD::Integer(mMaxJointsPerMesh);
+        mWarningsArray.append(args);
+        return LEGACY_RIG_FLAG_TOO_MANY_JOINTS;
     }
 
     // Unknown joints in asset
@@ -439,18 +441,24 @@ bool LLModelLoader::isRigLegacy( const std::vector<std::string> &jointListFromAs
         if (mJointMap.find(*it)==mJointMap.end())
         {
             LL_WARNS() << "Rigged to unrecognized joint name " << *it << LL_ENDL;
-            mWarningStream << "Rigged to unrecognized joint name " << *it << "\n";
+            LLSD args;
+            args["Message"] = "UnrecognizedJoint";
+            args["[NAME]"] = *it;
+            mWarningsArray.append(args);
             unknown_joint_count++;
         }
     }
     if (unknown_joint_count>0)
     {
         LL_WARNS() << "Skinning disabled due to unknown joints" << LL_ENDL;
-        mWarningStream << "Skinning disabled due to unknown joints\n";
-        return false;
+        LLSD args;
+        args["Message"] = "UnknownJoints";
+        args["[COUNT]"] = LLSD::Integer(unknown_joint_count);
+        mWarningsArray.append(args);
+        return LEGACY_RIG_FLAG_UNKNOWN_JOINT;
     }
 
-	return true;
+    return LEGACY_RIG_OK;
 }
 //-----------------------------------------------------------------------------
 // isRigSuitableForJointPositionUpload()
diff --git a/indra/llprimitive/llmodelloader.h b/indra/llprimitive/llmodelloader.h
index 8dde176b542b944755572c2d4e8476b55ff98701..fbc74554a07f940b0e1c9e9b432d360c89d85b4c 100644
--- a/indra/llprimitive/llmodelloader.h
+++ b/indra/llprimitive/llmodelloader.h
@@ -42,6 +42,10 @@ typedef std::deque<std::string>						JointNameSet;
 const S32 SLM_SUPPORTED_VERSION	= 3;
 const S32 NUM_LOD						= 4;
 
+const U32 LEGACY_RIG_OK = 0;
+const U32 LEGACY_RIG_FLAG_TOO_MANY_JOINTS = 1;
+const U32 LEGACY_RIG_FLAG_UNKNOWN_JOINT = 2;
+
 class LLModelLoader : public LLThread
 {
 public:
@@ -166,7 +170,7 @@ class LLModelLoader : public LLThread
 	void critiqueRigForUploadApplicability( const std::vector<std::string> &jointListFromAsset );
 
 	//Determines if a rig is a legacy from the joint list
-	bool isRigLegacy( const std::vector<std::string> &jointListFromAsset );
+	U32 determineRigLegacyFlags( const std::vector<std::string> &jointListFromAsset );
 
 	//Determines if a rig is suitable for upload
 	bool isRigSuitableForJointPositionUpload( const std::vector<std::string> &jointListFromAsset );
@@ -174,8 +178,9 @@ class LLModelLoader : public LLThread
 	const bool isRigValidForJointPositionUpload( void ) const { return mRigValidJointUpload; }
 	void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
 
-	const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
-	void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }		
+	const bool isLegacyRigValid(void) const { return mLegacyRigFlags == 0; }
+	U32 getLegacyRigFlags() const { return mLegacyRigFlags; }
+	void setLegacyRigFlags( U32 rigFlags ) { mLegacyRigFlags = rigFlags; }
 
 	//-----------------------------------------------------------------------------
 	// isNodeAJoint()
@@ -185,8 +190,8 @@ class LLModelLoader : public LLThread
 		return name != NULL && mJointMap.find(name) != mJointMap.end();
 	}
 
-	std::string logOut() { return mWarningStream.str(); }
-	void clearLog() { mWarningStream.clear(); }
+	const LLSD logOut() const { return mWarningsArray; }
+	void clearLog() { mWarningsArray.clear(); }
 
 protected:
 
@@ -197,14 +202,14 @@ class LLModelLoader : public LLThread
 	void*								mOpaqueData;
 
 	bool		mRigValidJointUpload;
-	bool		mLegacyRigValid;
+	U32			mLegacyRigFlags;
 
 	bool		mNoNormalize;
 	bool		mNoOptimize;
 
 	JointTransformMap	mJointTransformMap;
 
-	std::ostringstream mWarningStream; // preview floater will pull logs from here
+	LLSD mWarningsArray; // preview floater will pull logs from here
 
 	static std::list<LLModelLoader*> sActiveLoaderList;
 	static bool isAlive(LLModelLoader* loader) ;
diff --git a/indra/newview/llfloatermodelpreview.cpp b/indra/newview/llfloatermodelpreview.cpp
index e1665dc2552dd6ee059af1562f8b3db3316e14dc..b3012ed0254ed4f3ac1bef2553c64411059ba015 100644
--- a/indra/newview/llfloatermodelpreview.cpp
+++ b/indra/newview/llfloatermodelpreview.cpp
@@ -343,6 +343,9 @@ BOOL LLFloaterModelPreview::postBuild()
 	childDisable("upload_joints");
 	childDisable("lock_scale_if_joint_position");
 
+	childSetVisible("skin_too_many_joints", false);
+	childSetVisible("skin_unknown_joint", false);
+
 	initDecompControls();
 
 	LLView* preview_panel = getChild<LLView>("preview_panel");
@@ -1306,6 +1309,34 @@ void LLFloaterModelPreview::onMouseCaptureLostModelPreview(LLMouseHandler* handl
 //-----------------------------------------------------------------------------
 // addStringToLog()
 //-----------------------------------------------------------------------------
+//static
+void LLFloaterModelPreview::addStringToLog(const std::string& message, const LLSD& args, bool flash, S32 lod)
+{
+    if (sInstance && sInstance->hasString(message))
+    {
+        std::string str;
+        switch (lod)
+        {
+        case LLModel::LOD_IMPOSTOR: str = "LOD0 "; break;
+        case LLModel::LOD_LOW:      str = "LOD1 "; break;
+        case LLModel::LOD_MEDIUM:   str = "LOD2 "; break;
+        case LLModel::LOD_PHYSICS:  str = "PHYS "; break;
+        case LLModel::LOD_HIGH:     str = "LOD3 ";   break;
+        default: break;
+        }
+        
+        LLStringUtil::format_map_t args_msg;
+        LLSD::map_const_iterator iter = args.beginMap();
+        LLSD::map_const_iterator end = args.endMap();
+        for (; iter != end; ++iter)
+        {
+            args_msg[iter->first] = iter->second.asString();
+        }
+        str += sInstance->getString(message, args_msg);
+        sInstance->addStringToLogTab(str, flash);
+    }
+}
+
 // static
 void LLFloaterModelPreview::addStringToLog(const std::string& str, bool flash)
 {
@@ -1370,7 +1401,7 @@ LLModelPreview::LLModelPreview(S32 width, S32 height, LLFloater* fmp)
 , mLodsQuery()
 , mLodsWithParsingError()
 , mPelvisZOffset( 0.0f )
-, mLegacyRigValid( false )
+, mLegacyRigFlags( U32_MAX )
 , mRigValidJointUpload( false )
 , mPhysicsSearchLOD( LLModel::LOD_PHYSICS )
 , mResetJoints( false )
@@ -2160,7 +2191,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)
 	// Copy determinations about rig so UI will reflect them
 	//
 	setRigValidForJointPositionUpload(mModelLoader->isRigValidForJointPositionUpload());
-	setLegacyRigValid(mModelLoader->isLegacyRigValid());
+	setLegacyRigFlags(mModelLoader->getLegacyRigFlags());
 
 	mModelLoader->loadTextures() ;
 
@@ -3739,9 +3770,18 @@ void LLModelPreview::loadedCallback(
 	LLModelPreview* pPreview = static_cast< LLModelPreview* >(opaque);
 	if (pPreview && !LLModelPreview::sIgnoreLoadedCallback)
 	{
-		LLFloaterModelPreview::addStringToLog(pPreview->mModelLoader->logOut(), true);
-		pPreview->mModelLoader->clearLog();
-		pPreview->loadModelCallback(lod); // removes mModelLoader in some cases
+        const LLSD out = pPreview->mModelLoader->logOut();
+        LLSD::array_const_iterator iter_out = out.beginArray();
+        LLSD::array_const_iterator end_out = out.endArray();
+        for (; iter_out != end_out; ++iter_out)
+        {
+            if (iter_out->has("Message"))
+            {
+                LLFloaterModelPreview::addStringToLog(iter_out->get("Message"), *iter_out, true, pPreview->mModelLoader->mLod);
+            }
+        }
+        pPreview->mModelLoader->clearLog();
+        pPreview->loadModelCallback(lod); // removes mModelLoader in some cases
 	}
 
 }
@@ -3920,13 +3960,25 @@ BOOL LLModelPreview::render()
 
 	if (has_skin_weights && lodsReady())
 	{ //model has skin weights, enable view options for skin weights and joint positions
-		if (fmp && isLegacyRigValid() )
-		{
-			fmp->enableViewOption("show_skin_weight");
-			fmp->setViewOptionEnabled("show_joint_positions", skin_weight);	
-			mFMP->childEnable("upload_skin");
-			mFMP->childSetValue("show_skin_weight", skin_weight);
-		}
+        U32 flags = getLegacyRigFlags();
+        if (fmp)
+        {
+            if (flags == LEGACY_RIG_OK)
+            {
+                fmp->enableViewOption("show_skin_weight");
+                fmp->setViewOptionEnabled("show_joint_positions", skin_weight);
+                mFMP->childEnable("upload_skin");
+                mFMP->childSetValue("show_skin_weight", skin_weight);
+            }
+            else if ((flags & LEGACY_RIG_FLAG_TOO_MANY_JOINTS) > 0)
+            {
+                mFMP->childSetVisible("skin_too_many_joints", true);
+            }
+            else if ((flags & LEGACY_RIG_FLAG_UNKNOWN_JOINT) > 0)
+            {
+                mFMP->childSetVisible("skin_unknown_joint", true);
+            }
+        }
 	}
 	else
 	{
diff --git a/indra/newview/llfloatermodelpreview.h b/indra/newview/llfloatermodelpreview.h
index a080965ffc7f306ec44ac74c458c8589b2163b28..5bb6714099817be69a1120874c3f6eaf7640d4aa 100644
--- a/indra/newview/llfloatermodelpreview.h
+++ b/indra/newview/llfloatermodelpreview.h
@@ -94,7 +94,8 @@ class LLFloaterModelPreview : public LLFloaterModelUploadBase
 	/*virtual*/ void onClose(bool app_quitting);
 
 	static void onMouseCaptureLostModelPreview(LLMouseHandler*);
-	static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
+    static void setUploadAmount(S32 amount) { sUploadAmount = amount; }
+    static void addStringToLog(const std::string& message, const LLSD& args, bool flash, S32 lod = -1);
 	static void addStringToLog(const std::string& str, bool flash);
 	static void addStringToLog(const std::ostringstream& strm, bool flash);
 
@@ -308,8 +309,9 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 	void setRigValidForJointPositionUpload( bool rigValid ) { mRigValidJointUpload = rigValid; }
 
 	//Accessors for the legacy rigs
-	const bool isLegacyRigValid( void ) const { return mLegacyRigValid; }
-	void setLegacyRigValid( bool rigValid ) { mLegacyRigValid = rigValid; }		
+	const bool isLegacyRigValid( void ) const { return mLegacyRigFlags == 0; }
+	U32 getLegacyRigFlags() const { return mLegacyRigFlags; }
+	void setLegacyRigFlags( U32 rigFlags ) { mLegacyRigFlags = rigFlags; }
 
 	static void	textureLoadedCallback( BOOL success, LLViewerFetchedTexture *src_vi, LLImageRaw* src, LLImageRaw* src_aux, S32 discard_level, BOOL final, void* userdata );
     static bool lodQueryCallback();
@@ -423,7 +425,7 @@ class LLModelPreview : public LLViewerDynamicTexture, public LLMutex
 	float		mPelvisZOffset;
 	
 	bool		mRigValidJointUpload;
-	bool		mLegacyRigValid;
+	U32			mLegacyRigFlags;
 
 	bool		mLastJointUpdate;
 
diff --git a/indra/newview/skins/default/xui/en/floater_model_preview.xml b/indra/newview/skins/default/xui/en/floater_model_preview.xml
index cbc5aeb37d6f3bcc2dea2d883cd37bfe23ff4e22..7e92e0360e28e187543254a170465c66c96fcaf7 100644
--- a/indra/newview/skins/default/xui/en/floater_model_preview.xml
+++ b/indra/newview/skins/default/xui/en/floater_model_preview.xml
@@ -38,6 +38,12 @@
   <string name="decomposing">Analyzing...</string>
   <string name="simplifying">Simplifying...</string>
   <string name="tbd">TBD</string>
+  
+  <!-- Warnings from model loader-->
+  <string name="TooManyJoint">Skinning disabled due to too many joints: [JOINTS], maximum: [MAX]</string>
+  <string name="UnrecognizedJoint">Rigged to unrecognized joint name [NAME]</string>
+  <string name="UnknownJoints">Skinning disabled due to [COUNT] unknown joints</string>
+  
 
   <panel
     follows="top|left"
@@ -1184,20 +1190,41 @@
              label_text.text_color="White"
              name="upload_skin"
              top_pad="15"/>
+           <text
+             follows="top|left"
+             height="17"
+             left="40"
+             name="skin_too_many_joints"
+             text_color="Orange"
+             top_pad="-2"
+             width="150">
+             Too many skinned joints
+           </text>
+           <text
+             follows="top|left"
+             height="17"
+             left="40"
+             name="skin_unknown_joint"
+             text_color="Orange"
+             top_pad="-17"
+             width="150">
+             Model has an unknown joint(s)
+           </text>
            <check_box
              follows="top|left"
              height="15"
              label="Include joint positions"
              label_text.text_color="White"
              name="upload_joints"
-             top_pad="15"/>
+             left_delta="-20"
+             top_pad="1"/>
            <check_box
              follows="top|left"
              height="15"
              label="Lock scale if joint position defined"
              label_text.text_color="White"
              name="lock_scale_if_joint_position"
-             top_pad="15"/>
+             top_pad="16"/>
            <text
              follows="top|left"
              height="15"