diff --git a/ee/app/assets/javascripts/external_issues_list/components/external_issues_list_root.vue b/ee/app/assets/javascripts/external_issues_list/components/external_issues_list_root.vue
index 7f631caa213e1047b8e7fd9722aed04ca9a8debf..2016cfa157cfcd86665af5a3cf5ea7f7c942762e 100644
--- a/ee/app/assets/javascripts/external_issues_list/components/external_issues_list_root.vue
+++ b/ee/app/assets/javascripts/external_issues_list/components/external_issues_list_root.vue
@@ -1,7 +1,14 @@
 <script>
-import { GlButton, GlIcon, GlLink, GlSprintf, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
+import {
+  GlButton,
+  GlIcon,
+  GlLink,
+  GlSprintf,
+  GlSafeHtmlDirective as SafeHtml,
+  GlAlert,
+} from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
 
-import createFlash from '~/flash';
 import IssuableList from '~/issuable_list/components/issuable_list_root.vue';
 import {
   IssuableStates,
@@ -30,6 +37,7 @@ export default {
     GlIcon,
     GlLink,
     GlSprintf,
+    GlAlert,
     IssuableList,
     ExternalIssuesListEmptyState,
   },
@@ -70,6 +78,7 @@ export default {
         [IssuableStates.Closed]: 0,
         [IssuableStates.All]: 0,
       },
+      errorMessage: null,
     };
   },
   computed: {
@@ -173,11 +182,9 @@ export default {
       return filteredSearchValue;
     },
     onExternalIssuesQueryError(error, message) {
-      createFlash({
-        message: message || error.message,
-        captureError: true,
-        error,
-      });
+      this.errorMessage = message || error.message;
+
+      Sentry.captureException(error);
     },
     onIssuableListClickTab(selectedIssueState) {
       this.currentPage = 1;
@@ -225,7 +232,11 @@ export default {
 </script>
 
 <template>
+  <gl-alert v-if="errorMessage" class="gl-mt-3" variant="danger" :dismissible="false">
+    {{ errorMessage }}
+  </gl-alert>
   <issuable-list
+    v-else
     :namespace="projectFullPath"
     :tabs="$options.IssuableListTabs"
     :current-tab="currentState"
diff --git a/ee/spec/frontend/external_issues_list/components/external_issues_list_root_spec.js b/ee/spec/frontend/external_issues_list/components/external_issues_list_root_spec.js
index 6e62fb633b686a656e2ab0a37758f497a2313a6b..ac87cc920818629d4923f62c9440e76431662eb9 100644
--- a/ee/spec/frontend/external_issues_list/components/external_issues_list_root_spec.js
+++ b/ee/spec/frontend/external_issues_list/components/external_issues_list_root_spec.js
@@ -1,3 +1,5 @@
+import { GlAlert } from '@gitlab/ui';
+import * as Sentry from '@sentry/browser';
 import { shallowMount, createLocalVue, mount } from '@vue/test-utils';
 import MockAdapter from 'axios-mock-adapter';
 import VueApollo from 'vue-apollo';
@@ -8,7 +10,6 @@ import jiraIssuesResolver from 'ee/integrations/jira/issues_list/graphql/resolve
 import createMockApollo from 'helpers/mock_apollo_helper';
 import waitForPromises from 'helpers/wait_for_promises';
 
-import createFlash from '~/flash';
 import IssuableList from '~/issuable_list/components/issuable_list_root.vue';
 import { i18n } from '~/issues_list/constants';
 import axios from '~/lib/utils/axios_utils';
@@ -61,9 +62,21 @@ describe('ExternalIssuesListRoot', () => {
   const mockLabel = 'ecosystem';
 
   const findIssuableList = () => wrapper.findComponent(IssuableList);
+  const findAlert = () => wrapper.findComponent(GlAlert);
   const createLabelFilterEvent = (data) => ({ type: 'labels', value: { data } });
   const createSearchFilterEvent = (data) => ({ type: 'filtered-search-term', value: { data } });
 
+  const expectErrorHandling = (expectedRenderedErrorMessage) => {
+    const issuesList = findIssuableList();
+    const alert = findAlert();
+
+    expect(issuesList.exists()).toBe(false);
+
+    expect(alert.exists()).toBe(true);
+    expect(alert.text()).toBe(expectedRenderedErrorMessage);
+    expect(Sentry.captureException).toHaveBeenCalledWith(expect.any(Error));
+  };
+
   const createComponent = ({
     apolloProvider = createMockApolloProvider(),
     provide = mockProvide,
@@ -300,13 +313,17 @@ describe('ExternalIssuesListRoot', () => {
   });
 
   describe('error handling', () => {
+    beforeEach(() => {
+      jest.spyOn(Sentry, 'captureException');
+    });
+
     describe('when request fails', () => {
       it.each`
         APIErrors        | expectedRenderedErrorMessage
         ${['API error']} | ${'API error'}
         ${undefined}     | ${i18n.errorFetchingIssues}
       `(
-        'calls `createFlash` with "$expectedRenderedErrorMessage" when API responds with "$APIErrors"',
+        'displays error alert with "$expectedRenderedErrorMessage" when API responds with "$APIErrors"',
         async ({ APIErrors, expectedRenderedErrorMessage }) => {
           jest.spyOn(axios, 'get');
           mock
@@ -316,17 +333,13 @@ describe('ExternalIssuesListRoot', () => {
           createComponent();
           await waitForPromises();
 
-          expect(createFlash).toHaveBeenCalledWith({
-            message: expectedRenderedErrorMessage,
-            captureError: true,
-            error: expect.any(Object),
-          });
+          expectErrorHandling(expectedRenderedErrorMessage);
         },
       );
     });
 
     describe('when GraphQL network error is encountered', () => {
-      it('calls `createFlash` correctly with default error message', async () => {
+      it('displays error alert with default error message', async () => {
         createComponent({
           apolloProvider: createMockApolloProvider({
             Query: {
@@ -336,35 +349,24 @@ describe('ExternalIssuesListRoot', () => {
         });
         await waitForPromises();
 
-        expect(createFlash).toHaveBeenCalledWith({
-          message: i18n.errorFetchingIssues,
-          captureError: true,
-          error: expect.any(Object),
-        });
+        expectErrorHandling(i18n.errorFetchingIssues);
       });
     });
   });
 
   describe('pagination', () => {
     it.each`
-      scenario                 | issuesListLoadFailed | issues                | shouldShowPaginationControls
-      ${'fails'}               | ${true}              | ${[]}                 | ${false}
-      ${'returns no issues'}   | ${false}             | ${[]}                 | ${false}
-      ${`returns some issues`} | ${false}             | ${mockExternalIssues} | ${true}
+      scenario                 | issues                | shouldShowPaginationControls
+      ${'returns no issues'}   | ${[]}                 | ${false}
+      ${`returns some issues`} | ${mockExternalIssues} | ${true}
     `(
       'sets `showPaginationControls` prop to $shouldShowPaginationControls when request $scenario',
-      async ({ issuesListLoadFailed, issues, shouldShowPaginationControls }) => {
+      async ({ issues, shouldShowPaginationControls }) => {
         jest.spyOn(axios, 'get');
-        mock
-          .onGet(mockProvide.issuesFetchPath)
-          .replyOnce(
-            issuesListLoadFailed ? httpStatus.INTERNAL_SERVER_ERROR : httpStatus.OK,
-            issues,
-            {
-              'x-page': 1,
-              'x-total': issues.length,
-            },
-          );
+        mock.onGet(mockProvide.issuesFetchPath).replyOnce(httpStatus.OK, issues, {
+          'x-page': 1,
+          'x-total': issues.length,
+        });
 
         createComponent();
         await waitForPromises();