Repository: globus/globus-cli

Issue:
Error with command: globus gcs collection create guest
Command generates error without much additional info. 

Command:
globus gcs collection create guest --user-credential-id <credential ID> <collection ID> /path/to/shared_dir test

Error:
AttributeError: 'str' object has no attribute 'get'

Comments:

Patch:
diff --git a/changelog.d/20240103_182435_sirosen_handle_non_dict_gcs_detail.md b/changelog.d/20240103_182435_sirosen_handle_non_dict_gcs_detail.md
new file mode 100644
index 0000000..75b9aba
--- /dev/null
+++ b/changelog.d/20240103_182435_sirosen_handle_non_dict_gcs_detail.md
@@ -0,0 +1,4 @@
+### Bugfixes
+
+* Fix the error handling when `globus gcs collection create guest` encounters a
+  non-session error.
diff --git a/src/globus_cli/commands/collection/create/guest.py b/src/globus_cli/commands/collection/create/guest.py
index d270c84..e89b864 100644
--- a/src/globus_cli/commands/collection/create/guest.py
+++ b/src/globus_cli/commands/collection/create/guest.py
@@ -197,7 +197,11 @@ def _is_session_timeout_error(e: globus_sdk.GCSAPIError) -> bool:
     Detect session timeouts related to HA collections.
     This is a hacky workaround until we have better GARE support across the CLI.
     """
-    detail_type = getattr(e, "detail", {}).get("DATA_TYPE")
+    detail = getattr(e, "detail", {})
+    if not isinstance(detail, dict):
+        return False
+
+    detail_type = detail.get("DATA_TYPE")
     return (
         e.http_status == 403
         and isinstance(detail_type, str)


Test patch:
diff --git a/tests/functional/collection/test_collection_create_guest.py b/tests/functional/collection/test_collection_create_guest.py
index d295755..e57392f 100644
--- a/tests/functional/collection/test_collection_create_guest.py
+++ b/tests/functional/collection/test_collection_create_guest.py
@@ -228,3 +228,44 @@ def test_guest_collection_create__when_session_times_out_against_ha_mapped_colle
 
     assert "Session timeout detected; Re-authentication required." in result.stderr
     assert f"globus login --gcs {endpoint_id} --force" in result.stderr
+
+
+def test_guest_collection_create__when_gcs_emits_unrecognized_error(
+    run_line,
+    mock_user_data,
+    add_gcs_login,
+):
+    meta = load_response_set("cli.collection_operations").metadata
+    mapped_collection_id = meta["mapped_collection_id"]
+    display_name = meta["guest_display_name"]
+    gcs_hostname = meta["gcs_hostname"]
+    endpoint_id = meta["endpoint_id"]
+    add_gcs_login(endpoint_id)
+
+    create_guest_collection_route = f"https://{gcs_hostname}/api/collections"
+    responses.replace(
+        "POST",
+        create_guest_collection_route,
+        status=403,
+        json={
+            "DATA_TYPE": "result#1.0.0",
+            "code": "permission_denied",
+            "detail": "oh noez!",
+            "has_next_page": False,
+            "http_response_code": 403,
+            "message": "Oh noez! You must authenticate much better!",
+        },
+    )
+
+    get_endpoint_route = (
+        f"{get_service_url('transfer')}v0.10/endpoint/{mapped_collection_id}"
+    )
+    get_endpoint_resp = requests.get(get_endpoint_route).json()
+    get_endpoint_resp["high_assurance"] = True
+    responses.replace("GET", get_endpoint_route, json=get_endpoint_resp)
+
+    params = f"{mapped_collection_id} /home/ '{display_name}'"
+    result = run_line(f"globus collection create guest {params}", assert_exit_code=1)
+
+    assert "Session timeout detected" not in result.stderr
+    assert "Oh noez! You must authenticate much better!" in result.stderr