Skip to content

Commit 4edf2f7

Browse files
committed
fix: prevent panic in validateAlertmanagerConfig on nil interface values
Signed-off-by: SungJin1212 <tjdwls1201@gmail.com>
1 parent a8c6358 commit 4edf2f7

3 files changed

Lines changed: 38 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
* [BUGFIX] Distributor: Return HTTP 499 (Client Closed Request) instead of 500 when a remote-write or OTLP push is canceled by the client, so client-side cancellations are no longer counted as server-side errors. #7717
8787
* [BUGFIX] Querier: Fix gRPC `codes.Canceled` errors being mapped to HTTP 500 instead of 499 when a client cancels a query. #7738
8888
* [BUGFIX] Compactor: Fix spurious `bucket operation fail after retries` error logs emitted during partial block cleanup. #7749
89+
* [BUGFIX] Alertmanager: Fix panic in `validateAlertmanagerConfig` when receiver config traversal encounters nil interface values. #7751
8990

9091
## 1.21.1 2026-06-04
9192

pkg/alertmanager/api.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,12 +384,12 @@ var configValidators = map[reflect.Type]func(any) error{
384384
// first error or nil if validation succeeds.
385385
func validateAlertmanagerConfig(cfg any) error {
386386
v := reflect.ValueOf(cfg)
387-
t := v.Type()
388387

389388
// Skip invalid, the zero value or a nil pointer (checked by zero value).
390389
if !v.IsValid() || v.IsZero() {
391390
return nil
392391
}
392+
t := v.Type()
393393

394394
// If the input config is a pointer then we need to get its value.
395395
// At this point the pointer value can't be nil.

pkg/alertmanager/api_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1367,3 +1367,39 @@ func TestValidateAlertmanagerConfig(t *testing.T) {
13671367
})
13681368
}
13691369
}
1370+
1371+
func TestValidateAlertmanagerConfig_DoesNotPanicOnNilInterfaceValues(t *testing.T) {
1372+
tests := map[string]any{
1373+
"nil root interface": any(nil),
1374+
"map value nil interface": map[string]any{"test": nil},
1375+
"slice value nil interface": []any{nil},
1376+
}
1377+
1378+
for testName, input := range tests {
1379+
t.Run(testName, func(t *testing.T) {
1380+
require.NotPanics(t, func() {
1381+
err := validateAlertmanagerConfig(input)
1382+
assert.NoError(t, err)
1383+
})
1384+
})
1385+
}
1386+
}
1387+
1388+
func TestValidateAlertmanagerConfig_PagerdutyDetailsNullValue(t *testing.T) {
1389+
amCfg, err := config.Load(`
1390+
route:
1391+
receiver: pd
1392+
receivers:
1393+
- name: pd
1394+
pagerduty_configs:
1395+
- routing_key: "abc123"
1396+
details:
1397+
foo: null
1398+
`)
1399+
require.NoError(t, err)
1400+
1401+
require.NotPanics(t, func() {
1402+
err = validateAlertmanagerConfig(amCfg)
1403+
})
1404+
assert.NoError(t, err)
1405+
}

0 commit comments

Comments
 (0)