diff --git a/files/gitlab-ctl-commands/lib/gitlab_ctl/util.rb b/files/gitlab-ctl-commands/lib/gitlab_ctl/util.rb
index 8cd9c5ebcbb4f697c7c6b66b7eb34eb7c2fdc416_ZmlsZXMvZ2l0bGFiLWN0bC1jb21tYW5kcy9saWIvZ2l0bGFiX2N0bC91dGlsLnJi..37430d8bb4618d2b31eac8ce5ffd46772f53af26_ZmlsZXMvZ2l0bGFiLWN0bC1jb21tYW5kcy9saWIvZ2l0bGFiX2N0bC91dGlsLnJi 100644
--- a/files/gitlab-ctl-commands/lib/gitlab_ctl/util.rb
+++ b/files/gitlab-ctl-commands/lib/gitlab_ctl/util.rb
@@ -100,7 +100,11 @@
 
       # Parse enabled roles out of the attributes json file and return an Array of Strings
       def roles(base_path)
-        get_node_attributes(base_path)['roles'].select { |k, v| v.key?('enable') && v['enable'] }.keys
+        roles = get_node_attributes(base_path)['roles']
+
+        return [] unless roles.is_a?(Hash)
+
+        roles.select { |k, v| v.key?('enable') && v['enable'] }.keys
       end
 
       def delay_for(seconds)
diff --git a/spec/gitlab-ctl-commands/lib/util_spec.rb b/spec/gitlab-ctl-commands/lib/util_spec.rb
index 8cd9c5ebcbb4f697c7c6b66b7eb34eb7c2fdc416_c3BlYy9naXRsYWItY3RsLWNvbW1hbmRzL2xpYi91dGlsX3NwZWMucmI=..37430d8bb4618d2b31eac8ce5ffd46772f53af26_c3BlYy9naXRsYWItY3RsLWNvbW1hbmRzL2xpYi91dGlsX3NwZWMucmI= 100644
--- a/spec/gitlab-ctl-commands/lib/util_spec.rb
+++ b/spec/gitlab-ctl-commands/lib/util_spec.rb
@@ -83,6 +83,20 @@
       allow(File).to receive(:read).with(fake_node_file).and_return(roled_node.to_json)
       expect(described_class.roles(fake_base_path)).to eq(%w[role_one role_three])
     end
+
+    it 'when no roles are defined' do
+      roled_node = {}
+      allow(File).to receive(:read).with(fake_node_file).and_return(roled_node.to_json)
+
+      expect(described_class.roles(fake_base_path)).to eq([])
+    end
+
+    it 'when roles is not a Hash' do
+      roled_node = { roles: "test" }
+      allow(File).to receive(:read).with(fake_node_file).and_return(roled_node.to_json)
+
+      expect(described_class.roles(fake_base_path)).to eq([])
+    end
   end
 
   describe '#parse_json_file' do