Folder interface hangs if there are file name clashes 
If I load some files into a resource, then put them in a folder, then out of a zip file get a file name with the same name as a file in the folder and try drag that into the folder the interface results in an indefinite spinning wheel.  I would like it to say that I am not allowed to do that due to overwriting, or give me a warning that I am about to overwrite.  It should not just hang.
diff --git a/hs_core/tests/api/native/test_resource_file_folder_operations.py b/hs_core/tests/api/native/test_resource_file_folder_operations.py
index 39e38414a..ec408ec2f 100644
--- a/hs_core/tests/api/native/test_resource_file_folder_operations.py
+++ b/hs_core/tests/api/native/test_resource_file_folder_operations.py
@@ -8,6 +8,7 @@ from hs_core.models import GenericResource, ResourceFile
 from hs_core.testing import MockIRODSTestCaseMixin
 from hs_core.views.utils import create_folder, move_or_rename_file_or_folder, zip_folder, \
     unzip_file, remove_folder
+from django_irods.icommands import SessionException
 
 
 class TestResourceFileFolderOprsAPI(MockIRODSTestCaseMixin, TransactionTestCase):
@@ -128,7 +129,35 @@ class TestResourceFileFolderOprsAPI(MockIRODSTestCaseMixin, TransactionTestCase)
         self.assertEqual(self.new_res.files.all().count(), 2,
                          msg="resource file count didn't match")
 
-        # unzip the file
+        # test unzip does not allow override of existing files
+        # add an existing file in the zip to the resource
+        hydroshare.add_resource_files(self.new_res.short_id, self.test_file_1)
+        create_folder(self.new_res.short_id, 'data/contents/sub_test_dir')
+        move_or_rename_file_or_folder(self.user_creator, self.new_res.short_id,
+                                      'data/contents/file1.txt',
+                                      'data/contents/sub_test_dir/file1.txt')
+        # Now resource should contain three files: file3_new.txt, sub_test_dir.zip, and file1.txt
+        self.assertEqual(self.new_res.files.all().count(), 3,
+                         msg="resource file count didn't match")
+        with self.assertRaises(SessionException):
+            unzip_file(self.user_creator, self.new_res.short_id, 'data/contents/sub_test_dir.zip',
+                       False)
+
+        # Resource should still contain three files: file3_new.txt, sub_test_dir.zip, and file1.txt
+        file_cnt = self.new_res.files.all().count()
+        self.assertEqual(file_cnt, 3,
+                         msg="resource file count didn't match - " + str(file_cnt) + " != 3")
+        with self.assertRaises(SessionException):
+            unzip_file(self.user_creator, self.new_res.short_id,
+                       'data/contents/sub_test_dir.zip',
+                       False)
+
+        # test unzipping the file succeeds now after deleting the existing file
+        remove_folder(self.user_creator, self.new_res.short_id, 'data/contents/sub_test_dir')
+        # Now resource should contain two files: file3_new.txt and sub_test_dir.zip
+        file_cnt = self.new_res.files.all().count()
+        self.assertEqual(file_cnt, 2,
+                         msg="resource file count didn't match - " + str(file_cnt) + " != 2")
         unzip_file(self.user_creator, self.new_res.short_id, 'data/contents/sub_test_dir.zip', True)
         # Now resource should contain three files: file1.txt, file2.txt, and file3_new.txt
         self.assertEqual(self.new_res.files.all().count(), 3,
diff --git a/hs_core/views/resource_folder_hierarchy.py b/hs_core/views/resource_folder_hierarchy.py
index 56dc5b806..4ef7c4c2e 100644
--- a/hs_core/views/resource_folder_hierarchy.py
+++ b/hs_core/views/resource_folder_hierarchy.py
@@ -27,21 +27,21 @@ def data_store_structure(request):
     """
     res_id = request.POST.get('res_id', None)
     if res_id is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - resource id is not included', status=400)
     res_id = str(res_id).strip()
     try:
         resource, _, _ = authorize(request, res_id,
                                    needed_permission=ACTION_TO_AUTHORIZE.VIEW_RESOURCE)
     except (NotFound, PermissionDenied):
-        # return permission defined response
-        return HttpResponse(content_type='application/json', status=403)
+        # return permission denied response
+        return HttpResponse('Permission denied', status=403)
 
     store_path = request.POST.get('store_path', None)
     if store_path is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - store_path is not included', status=400)
     store_path = str(store_path).strip()
     if not store_path:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - store_path cannot be empty', status=400)
     istorage = resource.get_irods_storage()
     if resource.resource_federation_path:
         res_coll = os.path.join(resource.resource_federation_path, res_id, store_path)
@@ -67,8 +67,7 @@ def data_store_structure(request):
                     break
             files.append({'name': fname, 'size': size, 'type': mtype, 'pk': f_pk, 'url': f_url})
     except SessionException as ex:
-        logger.error(ex.stderr)
-        return HttpResponse(content_type='application/json', status=500)
+        return HttpResponse(ex.stderr, status=500)
 
     return_object = {'files': files,
                      'folders': store[0]}
@@ -93,26 +92,26 @@ def data_store_folder_zip(request):
     """
     res_id = request.POST.get('res_id', None)
     if res_id is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - resource id is not included', status=400)
     res_id = str(res_id).strip()
     try:
         resource, _, user = authorize(request, res_id,
                                       needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE)
     except (NotFound, PermissionDenied):
-        # return permission defined response
-        return HttpResponse(content_type='application/json', status=403)
+        # return permission denied response
+        return HttpResponse('Permission denied', status=403)
     input_coll_path = request.POST.get('input_coll_path', None)
     if input_coll_path is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - input_coll_path is not included', status=400)
     input_coll_path = str(input_coll_path).strip()
     if not input_coll_path:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - input_coll_path cannot be empty', status=400)
     output_zip_fname = request.POST.get('output_zip_file_name', None)
     if output_zip_fname is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - output_zip_fname is not included', status=400)
     output_zip_fname = str(output_zip_fname).strip()
     if not output_zip_fname:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - output_zip_fname cannot be empty', status=400)
     remove_original = request.POST.get('remove_original_after_zip', None)
     bool_remove_original = True
     if remove_original:
@@ -124,8 +123,7 @@ def data_store_folder_zip(request):
         output_zip_fname, size = \
             zip_folder(user, res_id, input_coll_path, output_zip_fname, bool_remove_original)
     except SessionException as ex:
-        logger.error(ex.stderr)
-        return HttpResponse(content_type='application/json', status=500)
+        return HttpResponse(ex.stderr, status=500)
 
     return_object = {'name': output_zip_fname,
                      'size': size,
@@ -150,20 +148,20 @@ def data_store_folder_unzip(request):
     """
     res_id = request.POST.get('res_id', None)
     if res_id is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - resource id is not included', status=400)
     res_id = str(res_id).strip()
     try:
         resource, _, user = authorize(request, res_id,
                                       needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE)
     except (NotFound, PermissionDenied):
-        # return permission defined response
-        return HttpResponse(content_type='application/json', status=403)
+        # return permission denied response
+        return HttpResponse('Permission denied', status=403)
     zip_with_rel_path = request.POST.get('zip_with_rel_path', None)
     if zip_with_rel_path is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - zip_with_rel_path is not included', status=400)
     zip_with_rel_path = str(zip_with_rel_path).strip()
     if not zip_with_rel_path:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - zip_with_rel_path cannot be empty', status=400)
     remove_original = request.POST.get('remove_original_zip', None)
     bool_remove_original = True
     if remove_original:
@@ -174,8 +172,11 @@ def data_store_folder_unzip(request):
     try:
         unzip_file(user, res_id, zip_with_rel_path, bool_remove_original)
     except SessionException as ex:
-        logger.error(ex.stderr)
-        return HttpResponse(content_type='application/json', status=500)
+        specific_msg = "iRODS error resulted in unzip being cancelled. This may be due to " \
+                       "protection from overwriting existing files. Unzip in a different " \
+                       "location (e.g., folder) or move or rename the file being overwritten. " \
+                       "iRODS error follows: "
+        return HttpResponse(specific_msg + ex.stderr, status=500)
 
     # this unzipped_path can be used for POST request input to data_store_structure()
     # to list the folder structure after unzipping
@@ -198,27 +199,26 @@ def data_store_create_folder(request):
     """
     res_id = request.POST.get('res_id', None)
     if res_id is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - resource id is not included', status=400)
     res_id = str(res_id).strip()
     try:
         resource, _, _ = authorize(request, res_id,
                                    needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE)
     except (NotFound, PermissionDenied):
-        # return permission defined response
-        return HttpResponse(content_type='application/json', status=403)
+        # return permission denied response
+        return HttpResponse('Permission denied', status=403)
 
     folder_path = request.POST.get('folder_path', None)
     if folder_path is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - folder_path is not included', status=400)
     folder_path = str(folder_path).strip()
     if not folder_path:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - folder_path cannot be empty', status=400)
 
     try:
         create_folder(res_id, folder_path)
     except SessionException as ex:
-        logger.error(ex.stderr)
-        return HttpResponse(content_type='application/json', status=500)
+        return HttpResponse(ex.stderr, status=500)
 
     return_object = {'new_folder_rel_path': folder_path}
 
@@ -239,27 +239,26 @@ def data_store_remove_folder(request):
     """
     res_id = request.POST.get('res_id', None)
     if res_id is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - resource id is not included', status=400)
     res_id = str(res_id).strip()
     try:
         resource, _, user = authorize(request, res_id,
                                       needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE)
     except (NotFound, PermissionDenied):
-        # return permission defined response
-        return HttpResponse(content_type='application/json', status=403)
+        # return permission denied response
+        return HttpResponse('Permission denied', status=403)
 
     folder_path = request.POST.get('folder_path', None)
     if folder_path is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - folder_path is not included', status=400)
     folder_path = str(folder_path).strip()
     if not folder_path:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - folder_path cannot be empty', status=400)
 
     try:
         remove_folder(user, res_id, folder_path)
     except SessionException as ex:
-        logger.error(ex.stderr)
-        return HttpResponse(content_type='application/json', status=500)
+        return HttpResponse(ex.stderr, status=500)
 
     return_object = {'status': 'success'}
     return HttpResponse(
@@ -279,29 +278,28 @@ def data_store_file_or_folder_move_or_rename(request):
     """
     res_id = request.POST.get('res_id', None)
     if res_id is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - resource id is not included', status=400)
     res_id = str(res_id).strip()
     try:
         resource, _, user = authorize(request, res_id,
                                       needed_permission=ACTION_TO_AUTHORIZE.EDIT_RESOURCE)
     except (NotFound, PermissionDenied):
-        # return permission defined response
-        return HttpResponse(content_type='application/json', status=403)
+        # return permission denied response
+        return HttpResponse('Permission denied', status=403)
 
     src_path = request.POST.get('source_path', None)
     tgt_path = request.POST.get('target_path', None)
     if src_path is None or tgt_path is None:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - src_path or tgt_path is not included', status=400)
     src_path = str(src_path).strip()
     tgt_path = str(tgt_path).strip()
     if not src_path or not tgt_path:
-        return HttpResponse(content_type='application/json', status=400)
+        return HttpResponse('Bad request - src_path or tgt_path cannot be empty', status=400)
 
     try:
         move_or_rename_file_or_folder(user, res_id, src_path, tgt_path)
     except SessionException as ex:
-        logger.error(ex.stderr)
-        return HttpResponse(content_type='application/json', status=500)
+        return HttpResponse(ex.stderr, status=500)
 
     return_object = {'target_rel_path': tgt_path}
 
diff --git a/hs_core/views/utils.py b/hs_core/views/utils.py
index dcb8fa0a8..454985f1e 100755
--- a/hs_core/views/utils.py
+++ b/hs_core/views/utils.py
@@ -512,6 +512,8 @@ def remove_irods_folder_in_django(resource, istorage, foldername):
     :return:
     """
     if resource and istorage and foldername:
+        if not foldername.endswith('/'):
+            foldername += '/'
         if resource.resource_federation_path:
             res_file_set = ResourceFile.objects.filter(
                 object_id=resource.id, fed_resource_file_name_or_path__icontains=foldername)
@@ -587,7 +589,7 @@ def unzip_file(user, res_id, zip_with_rel_path, bool_remove_original):
 
     unzip_path = os.path.dirname(zip_with_full_path)
     zip_fname = os.path.basename(zip_with_rel_path)
-    istorage.session.run("ibun", None, '-xfDzip', zip_with_full_path, unzip_path)
+    istorage.session.run("ibun", None, '-xDzip', zip_with_full_path, unzip_path)
     link_irods_folder_to_django(resource, istorage, unzip_path, (zip_fname,))
 
     if bool_remove_original:
diff --git a/theme/static/js/hs_file_browser.js b/theme/static/js/hs_file_browser.js
index 87078a825..169d9d957 100644
--- a/theme/static/js/hs_file_browser.js
+++ b/theme/static/js/hs_file_browser.js
@@ -196,6 +196,11 @@ function bindFileBrowserItemEvents() {
                     refreshFileBrowser();
                     destination.removeClass("fb-drag-cutting");
                 });
+
+                $.when.apply($, calls).fail(function () {
+                    refreshFileBrowser();
+                    destination.removeClass("fb-drag-cutting");
+                });
                 
                 $("#fb-files-container li.ui-selected").fadeOut();
             },
@@ -476,6 +481,10 @@ function onOpenFolder() {
     $.when.apply($, calls).done(function () {
         updateSelectionMenuContext();
     });
+
+    $.when.apply($, calls).fail(function () {
+        updateSelectionMenuContext();
+    });
 }
 
 function updateNavigationState() {
@@ -501,6 +510,13 @@ function refreshFileBrowser() {
         sourcePaths = [];
         updateSelectionMenuContext();
     });
+
+    $.when.apply($, calls).fail(function () {
+        $("#fb-files-container li").removeClass("fb-cutting");
+        $(".selection-menu").hide();
+        sourcePaths = [];
+        updateSelectionMenuContext();
+    });
 }
 
 $(document).ready(function () {
@@ -764,6 +780,10 @@ $(document).ready(function () {
             $.when.apply($, calls).done(function () {
                 refreshFileBrowser();
             });
+
+            $.when.apply($, calls).fail(function () {
+                refreshFileBrowser();
+            });
         }
         return false;
     });
@@ -848,6 +868,13 @@ $(document).ready(function () {
             $("#fb-files-container li").removeClass("fb-cutting");
             updateSelectionMenuContext();
         });
+
+        $.when.apply($, calls).fail(function () {
+            refreshFileBrowser();
+            sourcePaths = [];
+            $("#fb-files-container li").removeClass("fb-cutting");
+            updateSelectionMenuContext();
+        });
     }
 
     // File(s) delete method
@@ -883,6 +910,16 @@ $(document).ready(function () {
                     refreshFileBrowser();
                 }
             });
+
+            $.when.apply($, calls).fail(function () {
+                if (filesToDelete != "") {
+                    $("#fb-delete-files-form input[name='file_ids']").val(filesToDelete);
+                    $("#fb-delete-files-form").submit();
+                }
+                else {
+                    refreshFileBrowser();
+                }
+            });
         }
     });
 
@@ -917,6 +954,10 @@ $(document).ready(function () {
         $.when.apply($, calls).done(function () {
             refreshFileBrowser();
         });
+
+        $.when.apply($, calls).fail(function () {
+            refreshFileBrowser();
+        });
     });
 
      // Download method
@@ -953,6 +994,10 @@ $(document).ready(function () {
             $.when.apply($, calls).done(function () {
                 refreshFileBrowser();
             });
+
+            $.when.apply($, calls).fail(function () {
+                refreshFileBrowser();
+            });
         }
     });
 
@@ -976,6 +1021,10 @@ $(document).ready(function () {
         $.when.apply($, calls).done(function () {
             refreshFileBrowser();
         });
+
+        $.when.apply($, calls).fail(function () {
+            refreshFileBrowser();
+        });
     });
 
     $(".selection-menu li").click(function () {
diff --git a/theme/static/js/resourceLandingAjax.js b/theme/static/js/resourceLandingAjax.js
index d156c7d8a..cc8c5d31e 100644
--- a/theme/static/js/resourceLandingAjax.js
+++ b/theme/static/js/resourceLandingAjax.js
@@ -472,6 +472,23 @@ function get_user_info_ajax_submit(url, obj) {
     });
 }
 
+function display_error_message(title, err_msg) {
+    $("#fb-alerts .upload-failed-alert").remove();
+    $("#hsDropzone").toggleClass("glow-blue", false);
+
+    $("#fb-alerts").append(
+        '<div class="alert alert-danger alert-dismissible upload-failed-alert" role="alert">' +
+        '<button type="button" class="close" data-dismiss="alert" aria-label="Close">' +
+        '<span aria-hidden="true">&times;</span></button>' +
+        '<div>' +
+        '<strong>' + title + '</strong>' +
+        '</div>' +
+        '<div>' +
+        '<span>' + err_msg + '</span>' +
+        '</div>' +
+        '</div>').fadeIn(200);
+}
+
 function delete_folder_ajax_submit(res_id, folder_path) {
     $(".file-browser-container, #fb-files-container").css("cursor", "progress");
 
@@ -486,6 +503,7 @@ function delete_folder_ajax_submit(res_id, folder_path) {
         success: function (result) {
         },
         error: function(xhr, errmsg, err){
+            display_error_message('Folder Deletion Failed', xhr.responseText);
         }
     });
 }
@@ -574,6 +592,7 @@ function zip_irods_folder_ajax_submit(res_id, input_coll_path, fileName) {
         success: function (result) {
         },
         error: function (xhr, errmsg, err) {
+            display_error_message('Folder Zipping Failed', xhr.responseText);
         }
     });
 }
@@ -593,7 +612,7 @@ function unzip_irods_file_ajax_submit(res_id, zip_with_rel_path) {
             // TODO: handle "File already exists" errors
         },
         error: function (xhr, errmsg, err) {
-
+            display_error_message('File Unzipping Failed', xhr.responseText);
         }
     });
 }
@@ -617,6 +636,7 @@ function create_irods_folder_ajax_submit(res_id, folder_path) {
 
         },
         error: function(xhr, errmsg, err){
+            display_error_message('Folder Creation Failed', xhr.responseText);
         }
     });
 }
@@ -639,6 +659,7 @@ function move_or_rename_irods_file_or_folder_ajax_submit(res_id, source_path, ta
             }
         },
         error: function(xhr, errmsg, err){
+            display_error_message('File Moving/Renaming Failed', xhr.responseText);
         }
     });
 }
\ No newline at end of file
['hs_core/views/resource_folder_hierarchy.py', 'theme/static/js/hs_file_browser.js', 'theme/static/js/resourceLandingAjax.js', 'hs_core/tests/api/native/test_resource_file_folder_operations.py', 'hs_core/views/utils.py']