diff --git a/static/app/views/automations/components/actionNodeList.spec.tsx b/static/app/views/automations/components/actionNodeList.spec.tsx
index 4c429928b9ef99..456e85430fc8d1 100644
--- a/static/app/views/automations/components/actionNodeList.spec.tsx
+++ b/static/app/views/automations/components/actionNodeList.spec.tsx
@@ -151,6 +151,30 @@ describe('ActionNodeList', () => {
expect(mockOnDeleteRow).toHaveBeenCalledWith(slackAction.id);
});
+ it('shows an error for actions with unavailable handlers', async () => {
+ MockApiClient.addMockResponse({
+ url: `/organizations/${organization.slug}/available-actions/`,
+ body: [], // No available actions
+ });
+
+ const slackAction = ActionFixture();
+ render(
+
+
+ ,
+ {
+ organization,
+ }
+ );
+
+ expect(
+ await screen.findByText(
+ 'The Slack action is no longer available. Please remove and reconfigure this action.'
+ )
+ ).toBeInTheDocument();
+ expect(screen.getByRole('button', {name: 'Delete row'})).toBeInTheDocument();
+ });
+
it('shows a warning message for an incompatible action', async () => {
const model = new FormModel();
model.setInitialData({
diff --git a/static/app/views/automations/components/actionNodeList.tsx b/static/app/views/automations/components/actionNodeList.tsx
index 540ec67154887c..6c3eb49896e3c6 100644
--- a/static/app/views/automations/components/actionNodeList.tsx
+++ b/static/app/views/automations/components/actionNodeList.tsx
@@ -62,7 +62,8 @@ export function ActionNodeList({
onDeleteRow,
updateAction,
}: ActionNodeListProps) {
- const {data: availableActions = []} = useAvailableActionsQuery();
+ const {data: availableActions = [], isLoading: isLoadingActions} =
+ useAvailableActionsQuery();
const {errors, removeError} = useAutomationBuilderErrorContext();
const {connectedDetectors} = useConnectedDetectors();
@@ -110,9 +111,33 @@ export function ActionNodeList({
return (
{actions.map(action => {
+ if (isLoadingActions) {
+ return null;
+ }
const handler = getActionHandler(action, availableActions);
if (!handler) {
- return null;
+ const actionLabel = actionNodesMap.get(action.type)?.label;
+ return (
+ {
+ onDeleteRow(action.id);
+ }}
+ hasError
+ errorMessage={
+ actionLabel
+ ? t(
+ 'The %s action is no longer available. Please remove and reconfigure this action.',
+ actionLabel
+ )
+ : t(
+ 'The integration is no longer available. Please remove and reconfigure this action.'
+ )
+ }
+ >
+ {actionLabel ?? t('Unknown integration')}
+
+ );
}
const error = errors?.[action.id];
const warningMessage = getIncompatibleActionWarning(action, {