Repository: Shopify/shopify-cli (Ruby)

Issue:
[Bug]: <Shopifycli theme serve error>
### Please confirm that you have:

- [X] Searched [existing issues](https://github.com/Shopify/shopify-cli/issues) to see if your issue is a duplicate. (If you’ve found a duplicate issue, feel free to add additional information in a comment on it.)
- [X] Reproduced the issue in [the latest CLI version](https://github.com/Shopify/shopify-cli/releases).

### What type of project are you working on?

theme

### Expected behavior

It should load up the theme and give a link to view my theme locally

### Actual behavior

It throws an error
```
X An unexpected error occured.
        To submit an issue include the stack trace.
```

### Stack trace

```shell
X An unexpected error occured.
        To submit an issue include the stack trace.

C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/theme/dev_server.rb:83:in `rescue in start': undefined method `shop' for nil:NilClass (NoMethodError)
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/theme/dev_server.rb:29:in `start'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/project_types/theme/commands/serve.rb:25:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/command/sub_command.rb:16:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/command.rb:27:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/executor.rb:17:in `block (2 levels) in call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:37:in `block (2 levels) in with_logging'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb:169:in `with_id'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:36:in `block in with_logging'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-ui/lib/cli/ui.rb:176:in `log_output_to'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:35:in `with_logging'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/executor.rb:16:in `block in call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:45:in `block (2 levels) in with_traps'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:51:in `twrap'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:44:in `block in with_traps'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:51:in `twrap'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:43:in `with_traps'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/executor.rb:15:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/entry_point.rb:24:in `block in call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/monorail.rb:26:in `log'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/entry_point.rb:23:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/bin/shopify:50:in `block (2 levels) in <top (required)>'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb:75:in `handle_abort'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb:21:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/bin/shopify:49:in `block in <top (required)>'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/bin/shopify:59:in `<top 
(required)>'
        from C:/Ruby30-x64/bin/shopify:23:in `load'
        from C:/Ruby30-x64/bin/shopify:23:in `<main>'
C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/api.rb:74:in `block in request': 403 (ShopifyCLI::API::APIRequestForbiddenError)
{"errors":"Unauthorized Access"}
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/util.rb:172:in `retry_after'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/api.rb:89:in `request'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/admin_api.rb:92:in `block in rest_request'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/util.rb:172:in `retry_after'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/admin_api.rb:95:in `rest_request'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/theme/theme_admin_api.rb:36:in `rest_request'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/theme/theme_admin_api.rb:14:in `get'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/theme/development_theme.rb:48:in `exists?'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/theme/development_theme.rb:34:in `ensure_exists!'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/theme/development_theme.rb:71:in `find_or_create!'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/theme/dev_server.rb:31:in `start'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/project_types/theme/commands/serve.rb:25:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/command/sub_command.rb:16:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/command.rb:27:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/executor.rb:17:in `block (2 levels) in call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:37:in `block (2 levels) in with_logging'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-ui/lib/cli/ui/stdout_router.rb:169:in `with_id'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:36:in `block in with_logging'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-ui/lib/cli/ui.rb:176:in `log_output_to'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:35:in `with_logging'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/executor.rb:16:in `block in call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:45:in `block (2 levels) in with_traps'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:51:in `twrap'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:44:in `block in with_traps'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:51:in `twrap'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/executor.rb:43:in `with_traps'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/executor.rb:15:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/entry_point.rb:24:in `block in call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/monorail.rb:26:in `log'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/lib/shopify_cli/core/entry_point.rb:23:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/bin/shopify:50:in `block (2 levels) in <top (required)>'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb:75:in `handle_abort'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/vendor/deps/cli-kit/lib/cli/kit/error_handler.rb:21:in `call'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/bin/shopify:49:in `block in <top (required)>'
        from C:/Ruby30-x64/lib/ruby/gems/3.0.0/gems/shopify-cli-2.15.1/bin/shopify:59:in `<top 
(required)>'
        from C:/Ruby30-x64/bin/shopify:23:in `load'
        from C:/Ruby30-x64/bin/shopify:23:in `<main>'
```


### Reproduction steps

1. run theme init
2. cd into theme directory
3. login to your store using the owners account
4. run ``` shopify theme serve```

### Operating System

windows 10

### CLI version (run `shopify version` if you're not sure)

2.15.1

### Shell

Git Bash

### Ruby version (run `ruby -v` if you're not sure)

_No response_

### What language and version are you using in your application?
ruby 3.0.2p107


Discussion:
@karreiro We keep seeing this error. While I'm not an expert in the affected code, I assume something in here is most likely to be the cause: https://github.com/Shopify/shopify-cli/blob/9acc06d13a8be760ac2798bbea71211222cba5f2/lib/shopify_cli/theme/development_theme.rb#L33-L41

Unfortunately we're not surfacing the real error due to `theme.shop` here: https://github.com/Shopify/shopify-cli/blob/9acc06d13a8be760ac2798bbea71211222cba5f2/lib/shopify_cli/theme/dev_server.rb#L95

1. `theme&.shop`
2. Even that won't be sufficient, because the point is that `theme` is `nil` and that's not supposed to happen. Is there another error message that would apply reliably to this situation? I assume it's to do with [this](https://github.com/Shopify/shopify-cli/blob/9acc06d13a8be760ac2798bbea71211222cba5f2/lib/shopify_cli/theme/theme.rb#L105-L119) but hard for me to know without much more context.
3. If we can't say reliably what's happened, should we just add a line which will re-raise the original error, giving us more details and opportunity to fix:
    ```ruby
    raise unless theme
    ```
Thank you for the initial investigation, @amcaplan! I will keep those points in mind :)
Hey friend. I have a fix that worked for me. (after 4h~6h trying..)

On your browser:
1-login to your shopify partner account 
(https://www.shopify.com/partners)

2-create a staff account with a diferent email. 
  a-login to https://partners.shopify.com
  b-on your left sidebar click on staff (its the second option bottom to top)
  c-click on invite staff and put your second email here. yeah, youre gonna have 2 accounts for you. 
  d-give yourself all permissions by clicking on all checkboxes
  
On your browser (invite yourself again to work on your shop)
1-Navigate to your store URL: yourstore.myshopify.com/admin
2-Navigate to https://yourstore.myshopify.com/admin/settings/account
3-On the left sidebar, click on users and permissions (the 4th option top to bottom)
4-Invite your own staff account again.

On your browser (write down your shop password. you will need it later)
1-Navigate to https://yourstore.myshopify.com/admin/online_store/preferences
2-Navigate all the way down, write down the password it shows on the section "password protection"

Run on your terminal, inside the shopify project's folder:
shopify logout

On your browser:
logout from shopify partners
logout from shopify store

Then..

On your browser:
1-navigate to yourstore.myshopify.com + login to your STAFF ACCOUNT (the second email, not your shopify partner account)

On your terminal:
shopify login --store yourstore.myshopify.com
shopify theme serve
it should open a chrome window saying : you are authenticated, you can now close this window. (something like that)

On your browser:
a-go to http://127.0.0.1:9292/
b-it should prompt you to put your store password.
c-you should be able to see your local changes now <3

If it helped you, please consider giving it a thumbs up, so others can benefit from this solution, and not waste 4h-6h solving it from scratch as I had to.
> Hey friend. I have a fix that worked for me. (after 4h~6h trying..)
> 
> On your browser: 1-login to your shopify partner account (https://www.shopify.com/partners)
> 
> 2-create a staff account with a diferent email. a-login to https://partners.shopify.com b-on your left sidebar click on staff (its the second option bottom to top) c-click on invite staff and put your second email here. yeah, youre gonna have 2 accounts for you. d-give yourself all permissions by clicking on all checkboxes
> 
> On your browser (invite yourself again to work on your shop) 1-Navigate to your store URL: yourstore.myshopify.com/admin 2-Navigate to https://yourstore.myshopify.com/admin/settings/account 3-On the left sidebar, click on users and permissions (the 4th option top to bottom) 4-Invite your own staff account again.
> 
> On your browser (write down your shop password. you will need it later) 1-Navigate to https://yourstore.myshopify.com/admin/online_store/preferences 2-Navigate all the way down, write down the password it shows on the section "password protection"
> 
> Run on your terminal, inside the shopify project's folder: shopify logout
> 
> On your browser: logout from shopify partners logout from shopify store
> 
> Then..
> 
> On your browser: 1-navigate to yourstore.myshopify.com + login to your STAFF ACCOUNT (the second email, not your shopify partner account)
> 
> On your terminal: shopify login --store yourstore.myshopify.com shopify theme serve it should open a chrome window saying : you are authenticated, you can now close this window. (something like that)
> 
> On your browser: a-go to http://127.0.0.1:9292/ b-it should prompt you to put your store password. c-you should be able to see your local changes now <3
> 
> If it helped you, please consider giving it a thumbs up, so others can benefit from this solution, and not waste 4h-6h solving it from scratch as I had to.

This Worked!!!!
Thanks to you and everyone who tried to help. 



Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 764d79ebc4..ada9927246 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@ From version 2.6.0, the sections in this file adhere to the [keep a changelog](h
 
 ### Fixed
 * [#2121](https://github.com/Shopify/shopify-cli/pull/2121): Fix the hot-reload to work when the section name is not equal to the type
+* [#2183](https://github.com/Shopify/shopify-cli/pull/2183): Improve error message when suspended users run `theme serve`
 
 ## Version 2.15.1
 
diff --git a/lib/project_types/theme/messages/messages.rb b/lib/project_types/theme/messages/messages.rb
index aa6357b2f1..c652955ef3 100644
--- a/lib/project_types/theme/messages/messages.rb
+++ b/lib/project_types/theme/messages/messages.rb
@@ -8,8 +8,9 @@ module Messages
             Usage: {{command:%1$s theme [ %2$s ]}}
         HELP
         ensure_user_error: "You are not authorized to edit themes on %s.",
-        ensure_user_try_this: "Make sure you are a user of that store, and allowed to edit themes.",
-
+        ensure_user_try_this: <<~ENSURE_USER,
+          Check if your user is activated, has permission to edit themes at the store, and try to re-login.
+        ENSURE_USER
         init: {
           help: <<~HELP,
             {{command:%s theme init}}: Clones a Git repository to use as a starting point for building a new theme.
@@ -181,7 +182,7 @@ module Messages
           CUSTOMIZE_OR_PREVIEW
           ensure_user: <<~ENSURE_USER,
             You are not authorized to edit themes on %s.
-            Make sure you are a user of that store, and allowed to edit themes.
+            Check if your user is activated, has permission to edit themes at the store, and try to re-login.
           ENSURE_USER
           address_already_in_use: "The address \"%s\" is already in use.",
           try_port_option: "Use the --port=PORT option to serve the theme in a different port.",
diff --git a/lib/shopify_cli/theme/dev_server.rb b/lib/shopify_cli/theme/dev_server.rb
index 64703c640f..a41e71fd74 100644
--- a/lib/shopify_cli/theme/dev_server.rb
+++ b/lib/shopify_cli/theme/dev_server.rb
@@ -92,7 +92,8 @@ def start(ctx, root, host: "127.0.0.1", port: 9292, poll: false, editor_sync: fa
 
         rescue ShopifyCLI::API::APIRequestForbiddenError,
                ShopifyCLI::API::APIRequestUnauthorizedError
-          raise ShopifyCLI::Abort, @ctx.message("theme.serve.ensure_user", theme.shop)
+          shop = ShopifyCLI::AdminAPI.get_shop_or_abort(@ctx)
+          raise ShopifyCLI::Abort, @ctx.message("theme.serve.ensure_user", shop)
         rescue Errno::EADDRINUSE
           error_message = @ctx.message("theme.serve.address_already_in_use", address)
           help_message = @ctx.message("theme.serve.try_port_option")
diff --git a/lib/shopify_cli/theme/theme_admin_api.rb b/lib/shopify_cli/theme/theme_admin_api.rb
index 3be86f349b..3d8ac1bb3f 100644
--- a/lib/shopify_cli/theme/theme_admin_api.rb
+++ b/lib/shopify_cli/theme/theme_admin_api.rb
@@ -41,31 +41,46 @@ def rest_request(**args)
         )
       rescue ShopifyCLI::API::APIRequestForbiddenError,
              ShopifyCLI::API::APIRequestUnauthorizedError => error
+
+        ##
         # The Admin API returns 403 Forbidden responses on different
         # scenarios:
         #
         # * when a user doesn't have permissions for a request:
-        #   <APIRequestForbiddenError: 403 {}>
+        #   - <APIRequestForbiddenError: 403 {}>
+        #   - <APIRequestForbiddenError: 403 {"errors":"Unauthorized Access"}>
         #
         # * when an asset operation cannot be performed:
-        #   <APIRequestForbiddenError: 403 {"message":"templates/gift_card.liquid could not be deleted"}>
-        if empty_response_error?(error)
-          return handle_permissions_error
+        #   - <APIRequestForbiddenError: 403 {"message":"templates/gift_card.liquid could not be deleted"}>
+        #
+        if empty_response?(error) || unauthorized_response?(error)
+          return permission_error
         end
 
         raise error
       end
 
-      def handle_permissions_error
+      def permission_error
         ensure_user_error = @ctx.message("theme.ensure_user_error", shop)
         ensure_user_try_this = @ctx.message("theme.ensure_user_try_this")
 
         @ctx.abort(ensure_user_error, ensure_user_try_this)
       end
 
-      def empty_response_error?(error)
-        error_message = error&.response&.body.to_s
-        error_message.empty?
+      def empty_response?(error)
+        response_body(error).empty?
+      end
+
+      def unauthorized_response?(error)
+        parsed_body = JSON.parse(response_body(error))
+        errors = parsed_body["errors"].to_s
+        errors.match?(/Unauthorized Access/)
+      rescue JSON::ParserError
+        false
+      end
+
+      def response_body(error)
+        error&.response&.body.to_s
       end
     end
   end


Test patch:
diff --git a/test/shopify-cli/theme/dev_server/integration_test.rb b/test/shopify-cli/theme/dev_server/integration_test.rb
index b8f69dbf9b..63a4381000 100644
--- a/test/shopify-cli/theme/dev_server/integration_test.rb
+++ b/test/shopify-cli/theme/dev_server/integration_test.rb
@@ -160,6 +160,23 @@ def test_streams_hot_reload_events
           socket.close
         end
 
+        def test_forbidden_error
+          start_server_and_wait_sync_files
+          error_message = "error message"
+          shop = "dev-theme-server-store.myshopify.com"
+
+          ShopifyCLI::Theme::DevelopmentTheme.stubs(:find_or_create!).raises(ShopifyCLI::API::APIRequestForbiddenError)
+
+          @ctx.stubs(:message).with("theme.serve.ensure_user", shop).returns(error_message)
+          @ctx.output_captured = true
+          io = capture_io_and_assert_raises(ShopifyCLI::Abort) do
+            DevServer.start(@ctx, "#{ShopifyCLI::ROOT}/test/fixtures/theme", port: @@port)
+          end
+          @ctx.output_captured = false
+
+          assert_message_output(io: io, expected_content: [error_message])
+        end
+
         private
 
         def start_server
diff --git a/test/shopify-cli/theme/development_theme_test.rb b/test/shopify-cli/theme/development_theme_test.rb
index 8c14101ae4..6504948162 100644
--- a/test/shopify-cli/theme/development_theme_test.rb
+++ b/test/shopify-cli/theme/development_theme_test.rb
@@ -45,6 +45,35 @@ def test_creates_development_theme_if_missing_from_storage
         @theme.ensure_exists!
       end
 
+      def test_creates_development_theme_when_an_unauthorized_error_happens
+        shop = "dev-theme-server-store.myshopify.com"
+        theme_id = "12345678"
+        error_message = "error message"
+        try_this_message = "try this message"
+        unauthorized_error_response = stub(body: '{"errors":"Unauthorized Access"}')
+        unauthorized_error = ShopifyCLI::API::APIRequestForbiddenError.new("403", response: unauthorized_error_response)
+
+        ShopifyCLI::AdminAPI.stubs(:get_shop_or_abort).returns(shop)
+        ShopifyCLI::DB.stubs(:get).with(:development_theme_id).returns(theme_id)
+
+        ShopifyCLI::AdminAPI.expects(:rest_request).with(
+          @ctx,
+          shop: shop,
+          api_version: "unstable",
+          method: "GET",
+          path: "themes/#{theme_id}.json",
+        ).raises(unauthorized_error)
+
+        @ctx.expects(:message).with("theme.ensure_user_error", shop).returns(error_message)
+        @ctx.expects(:message).with("theme.ensure_user_try_this").returns(try_this_message)
+
+        io = capture_io_and_assert_raises(ShopifyCLI::AbortSilent) do
+          @theme.ensure_exists!
+        end
+
+        assert_message_output(io: io, expected_content: [error_message, try_this_message])
+      end
+
       def test_creates_development_theme_if_missing_from_api
         shop = "dev-theme-server-store.myshopify.com"
         theme_name = "Development (5676d8-theme-dev)"
diff --git a/test/shopify-cli/theme/theme_admin_api_test.rb b/test/shopify-cli/theme/theme_admin_api_test.rb
index 2136997a92..455cee5fc2 100644
--- a/test/shopify-cli/theme/theme_admin_api_test.rb
+++ b/test/shopify-cli/theme/theme_admin_api_test.rb
@@ -134,13 +134,9 @@ def test_does_not_pass_nil_arguments
 
       def test_graceullly_handles_api_permissions_errors
         path = "themes.json"
-        request_params = {
-          method: "POST",
-          path: path,
-        }
 
         ShopifyCLI::AdminAPI.expects(:rest_request)
-          .with(@ctx, shop: @shop, api_version: @api_version, **request_params)
+          .with(@ctx, shop: @shop, api_version: @api_version, method: "POST", path: path)
           .raises(ShopifyCLI::API::APIRequestForbiddenError)
 
         @ctx.expects(:message).with("theme.ensure_user_error", @shop).returns("ensure_user_error")
@@ -152,6 +148,24 @@ def test_graceullly_handles_api_permissions_errors
         )
       end
 
+      def test_forbiden_errors_related_to_unauthorized_access
+        path = "themes.json"
+        error_response = stub(body: '{"errors":"Unauthorized Access"}')
+        expected_error = ShopifyCLI::API::APIRequestForbiddenError.new("403", response: error_response)
+
+        ShopifyCLI::AdminAPI.expects(:rest_request)
+          .with(@ctx, shop: @shop, api_version: @api_version, method: "POST", path: path)
+          .raises(expected_error)
+
+        @ctx.expects(:message).with("theme.ensure_user_error", @shop).returns("ensure_user_error")
+        @ctx.expects(:message).with("theme.ensure_user_try_this").returns("ensure_user_try_this")
+        @ctx.expects(:abort).with("ensure_user_error", "ensure_user_try_this")
+
+        @api_client.post(
+          path: path
+        )
+      end
+
       def test_forbiden_errors_not_related_to_unauthorized_access
         path = "themes.json"
         error_response = stub(body: '{"message":"templates/gift_card.liquid could not be deleted"}')
@@ -168,6 +182,50 @@ def test_forbiden_errors_not_related_to_unauthorized_access
         assert_equal(expected_error, actual_error)
       end
 
+      def test_unauthorized_response_with_nil_error
+        error = nil
+        refute(@api_client.send(:unauthorized_response?, error))
+      end
+
+      def test_unauthorized_response_with_nil_response
+        error = stub(response: nil)
+        refute(@api_client.send(:unauthorized_response?, error))
+      end
+
+      def test_unauthorized_response_with_nil_body
+        response = stub(body: nil)
+        error = stub(response: response)
+        refute(@api_client.send(:unauthorized_response?, error))
+      end
+
+      def test_unauthorized_response_with_invalid_json
+        body = '{"errors":"Unauthorized Access")))'
+        response = stub(body: body)
+        error = stub(response: response)
+        refute(@api_client.send(:unauthorized_response?, error))
+      end
+
+      def test_unauthorized_response_with_no_error
+        body = '{"message":"templates/gift_card.liquid could not be deleted"}'
+        response = stub(body: body)
+        error = stub(response: response)
+        refute(@api_client.send(:unauthorized_response?, error))
+      end
+
+      def test_unauthorized_response_with_unauthorized_error
+        body = '{"errors":"Unauthorized Access"}'
+        response = stub(body: body)
+        error = stub(response: response)
+        assert(@api_client.send(:unauthorized_response?, error))
+      end
+
+      def test_unauthorized_response_with_other_error
+        body = '{"errors":"500 Internal Server Error"}'
+        response = stub(body: body)
+        error = stub(response: response)
+        refute(@api_client.send(:unauthorized_response?, error))
+      end
+
       private
 
       def expect_correct_request_arguments(request_params)