From b74465e4280e4552def390ec34a1a17ed259a5ce Mon Sep 17 00:00:00 2001
From: Sonia Aguilar <33540275+soniaAguilarPeiron@users.noreply.github.com>
Date: Wed, 3 Dec 2025 12:33:48 +0100
Subject: [PATCH] Alerting: Fix 'Rule group does not exist' error toast
(#101949) (#114766)
Alerting: Fix "Rule group does not exist" error toast (#101949)
---
.../unified/hooks/useCombinedRule.test.tsx | 92 +++++++++++++++++++
.../alerting/unified/hooks/useCombinedRule.ts | 6 ++
2 files changed, 98 insertions(+)
create mode 100644 public/app/features/alerting/unified/hooks/useCombinedRule.test.tsx
diff --git a/public/app/features/alerting/unified/hooks/useCombinedRule.test.tsx b/public/app/features/alerting/unified/hooks/useCombinedRule.test.tsx
new file mode 100644
index 00000000000..9c1cf313d7c
--- /dev/null
+++ b/public/app/features/alerting/unified/hooks/useCombinedRule.test.tsx
@@ -0,0 +1,92 @@
+import { HttpResponse, http } from 'msw';
+import { render, screen, waitFor } from 'test/test-utils';
+
+import { AppNotificationList } from 'app/core/components/AppNotifications/AppNotificationList';
+import { AccessControlAction } from 'app/types/accessControl';
+import { GrafanaRuleIdentifier } from 'app/types/unified-alerting';
+
+import { setupMswServer } from '../mockApi';
+import { grantUserPermissions } from '../mocks';
+import { grafanaRulerNamespace, grafanaRulerRule } from '../mocks/grafanaRulerApi';
+import { GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource';
+
+import { useCombinedRule } from './useCombinedRule';
+
+const server = setupMswServer();
+
+beforeAll(() => {
+ grantUserPermissions([AccessControlAction.AlertingRuleExternalRead, AccessControlAction.AlertingRuleRead]);
+});
+
+// Test component that uses useCombinedRule hook
+const UseCombinedRuleTestComponent = ({ ruleIdentifier }: { ruleIdentifier: GrafanaRuleIdentifier }) => {
+ const { loading, error, result } = useCombinedRule({ ruleIdentifier });
+
+ return (
+ <>
+
+
{loading ? 'loading' : 'not-loading'}
+ {error ? 'has-error' : 'no-error'}
+ {result ? 'has-result' : 'no-result'}
+ >
+ );
+};
+
+describe('useCombinedRule', () => {
+ describe('when rule group returns 404', () => {
+ it('should not show error notification when rule group does not exist', async () => {
+ // Mock the getAlertRule endpoint to return a valid rule
+ server.use(
+ http.get('/api/ruler/grafana/api/v1/rule/:uid', () => {
+ return HttpResponse.json(grafanaRulerRule);
+ })
+ );
+
+ // Mock the ruler group endpoint to return 404 (simulating a new or deleted group)
+ server.use(
+ http.get('/api/ruler/grafana/api/v1/rules/:namespace/:group', () => {
+ return HttpResponse.json({ error: 'rule group does not exist' }, { status: 404 });
+ })
+ );
+
+ // Mock the prometheus rules endpoint
+ server.use(
+ http.get('/api/prometheus/grafana/api/v1/rules', () => {
+ return HttpResponse.json({
+ status: 'success',
+ data: { groups: [] },
+ });
+ })
+ );
+
+ // Mock the folder endpoint
+ server.use(
+ http.get('/api/folders/:uid', () => {
+ return HttpResponse.json({
+ uid: grafanaRulerNamespace.uid,
+ title: grafanaRulerNamespace.name,
+ });
+ })
+ );
+
+ const ruleIdentifier: GrafanaRuleIdentifier = {
+ ruleSourceName: GRAFANA_RULES_SOURCE_NAME,
+ uid: grafanaRulerRule.grafana_alert.uid,
+ };
+
+ render();
+
+ // Wait for the hook to finish loading
+ await waitFor(() => {
+ expect(screen.getByTestId('loading')).toHaveTextContent('not-loading');
+ });
+
+ // The hook should have an error (404)
+ expect(screen.getByTestId('error')).toHaveTextContent('has-error');
+
+ // Verify that no error notification was shown
+ // If showErrorAlert was true, we would see an alert with role="status"
+ expect(screen.queryByRole('status')).not.toBeInTheDocument();
+ });
+ });
+});
diff --git a/public/app/features/alerting/unified/hooks/useCombinedRule.ts b/public/app/features/alerting/unified/hooks/useCombinedRule.ts
index 4bb06a6c962..3fd0faeb783 100644
--- a/public/app/features/alerting/unified/hooks/useCombinedRule.ts
+++ b/public/app/features/alerting/unified/hooks/useCombinedRule.ts
@@ -68,6 +68,9 @@ export function useCloudCombinedRulesMatching(
rulerConfig: rulerConfig,
namespace: nsGroup.namespace.name,
group: nsGroup.group.name,
+ // Suppress error notifications for 404s - the group may not exist yet (new group)
+ // or may have been deleted (last rule removed)
+ notificationOptions: { showErrorAlert: false },
}).unwrap();
rulerGroups.push(rulerGroup);
})
@@ -145,6 +148,9 @@ export function useCombinedRule({ ruleIdentifier, limitAlerts }: Props): Request
rulerConfig: dsFeatures.rulerConfig,
namespace: ruleLocation.namespace,
group: ruleLocation.group,
+ // Suppress error notifications for 404s - the group may not exist yet (new group)
+ // or may have been deleted (last rule removed)
+ notificationOptions: { showErrorAlert: false },
});
}, [dsFeatures, fetchRulerRuleGroup, ruleLocation]);