Repository: cloudnative-pg/cloudnative-pg

Issue:
[Bug]: panic when using v1.Cluster in own operator
### Is there an existing issue already for this bug?

- [x] I have searched for an existing issue, and could not find anything. I believe this is a new bug.

### I have read the troubleshooting guide

- [x] I have read the troubleshooting guide and I think this is a new bug.

### I am running a supported version of CloudNativePG

- [x] I have read the troubleshooting guide and I think this is a new bug.

### Contact Details

sebastian@platform9.com

### Version

1.25 (latest patch)

### What version of Kubernetes are you using?

1.32

### What is your Kubernetes environment?

Self-managed: kind (evaluation)

### How did you install the operator?

Helm

### What happened?

We're building an in-house operator on top of CNPG and observing a panic in our own operator inside https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.19.4/pkg/controller/controllerutil#CreateOrUpdate when reconciling on a `Cluster`

```
an unexported field was encountered, nested like this: *v1.Cluster -> v1.Cluster -> v1.ClusterSpec -> *v1.ReplicationSlotsConfiguration -> v1.ReplicationSlotsConfiguration -> *v1.SynchronizeReplicasConfiguration -> v1.SynchronizeReplicasConfiguration -> v1.synchronizeReplicasCache -> bool
```

This is due to https://github.com/cloudnative-pg/cloudnative-pg/pull/3710/files#diff-23ef73aeeb33654fa19d5f71b6e2c231660b6ec9023ad82dd736918ce6950617R1004 introducing an unexported field without specifying an an Equality function, see https://github.com/cloudnative-pg/cloudnative-pg/pull/3710/files#diff-23ef73aeeb33654fa19d5f71b6e2c231660b6ec9023ad82dd736918ce6950617R1004 

It should be reproducable by calling `reflect.DeepEqual` on two `v1.Cluster`s with a trivially populated `SynchronizeReplicasConfiguration`. 

## Stacktrace

```
k8s.io/apimachinery/pkg/util/runtime.logPanic({0x1f4a378, 0x4000a58150}, {0x18f4280, 0x40009182b8})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/pkg/util/runtime/runtime.go:107 +0x98
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Reconcile.func1()
        /go/pkg/mod/sigs.k8s.io/controller-runtime@v0.19.1/pkg/internal/controller/controller.go:105 +0xf0
panic({0x18f4280?, 0x40009182b8?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x1bde9a0?, 0x4000378808?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x40009182a0?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x1ab3440?, 0x4000378808?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x4000918288?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x1bd7e20?, 0x4000378910?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x4000918270?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x196c2a0?, 0x4000378a08?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x4000918258?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x19c36a0?, 0x4000918108?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x4000918240?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x199e3a0?, 0x4000918118?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x4000918228?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x19c35e0?, 0x4000809260?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x4000918210?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x1a15e40?, 0x4000809280?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x40009181f8?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.makeUsefulPanic({0x17cf8c0?, 0x4000809298?, 0x400072d340?})
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:96 +0x134
panic({0x18f4280?, 0x40009181e0?})
        /usr/local/go/src/runtime/panic.go:785 +0x124
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x17cf8c0?, 0x4000809298?, 0x23164?}, {0x17cf8c0?, 0x40008091d8?, 0x2?}, 0x4000113a48, 0x1, 0x8)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:257 +0x1290
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x1a15e40?, 0x4000809280?, 0x1?}, {0x1a15e40?, 0x40008091c0?, 0x4000112b08?}, 0x4000113a48, 0x1, 0x7)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:206 +0x1310
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x19c35e0?, 0x4000809260?, 0x8?}, {0x19c35e0?, 0x40008091a0?, 0xffff5bf398d8?}, 0x4000113a48, 0x1, 0x6)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:206 +0x1310
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x199e3a0?, 0x4000918118?, 0x17cf4c0?}, {0x199e3a0?, 0x400012dc60?, 0x4000112f08?}, 0x4000113a48, 0x1, 0x5)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:203 +0xed0
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x19c36a0?, 0x4000918108?, 0x17cf4c0?}, {0x19c36a0?, 0x400012dc50?, 0x4000113118?}, 0x4000113a48, 0x1, 0x4)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:206 +0x1310
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x196c2a0?, 0x4000378a08?, 0x4000113300?}, {0x196c2a0?, 0x40005c9208?, 0x40005c9008?}, 0x4000113a48, 0x1, 0x3)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:203 +0xed0
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x1bd7e20?, 0x4000378910?, 0x0?}, {0x1bd7e20?, 0x40005c9110?, 0x0?}, 0x4000113a48, 0x1, 0x2)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:206 +0x1310
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x1ab3440?, 0x4000378808?, 0x7f98c?}, {0x1ab3440?, 0x40005c9008?, 0xffff5bef9fd0?}, 0x4000113a48, 0x1, 0x1)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:206 +0x1310
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepValueEqual(0x40000245d0, {0x1bde9a0?, 0x4000378808?, 0x17cf4c0?}, {0x1bde9a0?, 0x40005c9008?, 0x4000113a18?}, 0x4000113a48, 0x1, 0x0)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:203 +0xed0
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.deepEqual(0x40000245d0, {0x1bde9a0?, 0x4000378808?}, {0x1bde9a0?, 0x40005c9008?}, 0x1)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:289 +0x210
k8s.io/apimachinery/third_party/forked/golang/reflect.Equalities.DeepEqual(...)
        /go/pkg/mod/k8s.io/apimachinery@v0.31.1/third_party/forked/golang/reflect/deep_equal.go:273
sigs.k8s.io/controller-runtime/pkg/controller/controllerutil.CreateOrUpdate({0x1f4a378, 0x4000a58150}, {0x1f5b440, 0x40002d71f0}, {0x1f70a80, 0x40005c9008}, 0x1d11110)
        /go/pkg/mod/sigs.k8s.io/controller-runtime@v0.19.1/pkg/controller/controllerutil/controllerutil.go:312 +0x204
extensions.platform9.horse/extensions/internal/controller.(*ServicePostgresReconciler).Reconcile(0x400000db90, {0x1f4a378, 0x4000a58150}, {{{0x400016af00?, 0x0?}, {0x400016aee8?, 0x5?}}})
        /workspace/internal/controller/servicepostgres_controller.go:103 +0x2cc
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Reconcile(0x4000a580c0?, {0x1f4a378?, 0x4000a58150?}, {{{0x400016af00?, 0x0?}, {0x400016aee8?, 0x0?}}})
        /go/pkg/mod/sigs.k8s.io/controller-runtime@v0.19.1/pkg/internal/controller/controller.go:116 +0x9c
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).reconcileHandler(0x1f60e20, {0x1f4a3b0, 0x40006b8690}, {{{0x400016af00, 0x17}, {0x400016aee8, 0x16}}})
        /go/pkg/mod/sigs.k8s.io/controller-runtime@v0.19.1/pkg/internal/controller/controller.go:303 +0x2b0
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).processNextWorkItem(0x1f60e20, {0x1f4a3b0, 0x40006b8690})
        /go/pkg/mod/sigs.k8s.io/controller-runtime@v0.19.1/pkg/internal/controller/controller.go:263 +0x18c
sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func2.2()
        /go/pkg/mod/sigs.k8s.io/controller-runtime@v0.19.1/pkg/internal/controller/controller.go:224 +0x80
created by sigs.k8s.io/controller-runtime/pkg/internal/controller.(*Controller[...]).Start.func2 in goroutine 117
        /go/pkg/mod/sigs.k8s.io/controller-runtime@v0.19.1/pkg/internal/controller/controller.go:220 +0x3c8
```


### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Discussion:
@dosubot: Hi, @sebastian-philipp. I'm [Dosu](https://dosu.dev), and I'm helping the cloudnative-pg team manage their backlog. I'm marking this issue as stale.

**Issue Summary**
- The issue involves a panic in a custom operator using CloudNativePG's `v1.Cluster` type.
- The panic is caused by an unexported field lacking an Equality function, affecting reconciliation.
- The problem can be reproduced with `reflect.DeepEqual` on two `v1.Cluster` objects with `SynchronizeReplicasConfiguration`.
- No additional comments or activities have been made on this issue.

**Next Steps**
- Please confirm if this issue is still relevant to the latest version of the cloudnative-pg repository by commenting here.
- If no updates are provided, the issue will be automatically closed in 7 days.

Thank you for your understanding and contribution!@sebastian-philipp: unstale please@senorhesles: We are hitting this issue as well (CP4AIOPS at IBM).

Solution patch:
diff --git a/api/v1/cluster_funcs.go b/api/v1/cluster_funcs.go
index 3e1b08c5..7234cbcf 100644
--- a/api/v1/cluster_funcs.go
+++ b/api/v1/cluster_funcs.go
@@ -154,27 +154,47 @@ func (status *ClusterStatus) GetAvailableArchitecture(archName string) *Availabl
 	return nil
 }
 
-func (r *SynchronizeReplicasConfiguration) compileRegex() []error {
-	if r == nil {
-		return nil
+type regexErrors struct {
+	errs []error
+}
+
+func (r regexErrors) Error() string {
+	if len(r.errs) == 0 {
+		return ""
+	}
+	var sb strings.Builder
+	sb.WriteString("failed to compile regex patterns: ")
+	for _, err := range r.errs {
+		sb.WriteString(err.Error())
+		sb.WriteString("; ")
 	}
-	if r.compiled {
-		return r.compileErrors
+	return sb.String()
+}
+
+func (r *SynchronizeReplicasConfiguration) compileRegex() ([]regexp.Regexp, error) {
+	if r == nil {
+		return nil, nil
 	}
 
-	var errs []error
-	for _, pattern := range r.ExcludePatterns {
+	var (
+		compiledPatterns = make([]regexp.Regexp, len(r.ExcludePatterns))
+		compileErrors    []error
+	)
+
+	for idx, pattern := range r.ExcludePatterns {
 		re, err := regexp.Compile(pattern)
 		if err != nil {
-			errs = append(errs, err)
+			compileErrors = append(compileErrors, err)
 			continue
 		}
-		r.compiledPatterns = append(r.compiledPatterns, *re)
+		compiledPatterns[idx] = *re
 	}
 
-	r.compiled = true
-	r.compileErrors = errs
-	return errs
+	if len(compileErrors) > 0 {
+		return nil, regexErrors{errs: compileErrors}
+	}
+
+	return compiledPatterns, nil
 }
 
 // GetEnabled returns false if synchronized replication slots are disabled, defaults to true
@@ -186,8 +206,9 @@ func (r *SynchronizeReplicasConfiguration) GetEnabled() bool {
 }
 
 // ValidateRegex returns all the errors that happened during the regex compilation
-func (r *SynchronizeReplicasConfiguration) ValidateRegex() []error {
-	return r.compileRegex()
+func (r *SynchronizeReplicasConfiguration) ValidateRegex() error {
+	_, err := r.compileRegex()
+	return err
 }
 
 // IsExcludedByUser returns if a replication slot should not be reconciled on the replicas
@@ -196,12 +217,13 @@ func (r *SynchronizeReplicasConfiguration) IsExcludedByUser(slotName string) (bo
 		return false, nil
 	}
 
+	compiledPatterns, err := r.compileRegex()
 	// this is an unexpected issue, validation should happen at webhook level
-	if errs := r.compileRegex(); len(errs) > 0 {
-		return false, errs[0]
+	if err != nil {
+		return false, err
 	}
 
-	for _, re := range r.compiledPatterns {
+	for _, re := range compiledPatterns {
 		if re.MatchString(slotName) {
 			return true, nil
 		}
diff --git a/api/v1/cluster_types.go b/api/v1/cluster_types.go
index 9e3b35f9..21c43565 100644
--- a/api/v1/cluster_types.go
+++ b/api/v1/cluster_types.go
@@ -20,8 +20,6 @@ SPDX-License-Identifier: Apache-2.0
 package v1
 
 import (
-	"regexp"
-
 	monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/resource"
@@ -1123,18 +1121,6 @@ type SynchronizeReplicasConfiguration struct {
 	// List of regular expression patterns to match the names of replication slots to be excluded (by default empty)
 	// +optional
 	ExcludePatterns []string `json:"excludePatterns,omitempty"`
-
-	synchronizeReplicasCache `json:"-"`
-}
-
-// synchronizeReplicasCache contains the result of the regex compilation
-// +kubebuilder:object:generate:=false
-type synchronizeReplicasCache struct {
-	compiledPatterns []regexp.Regexp `json:"-"`
-
-	compiled bool `json:"-"`
-
-	compileErrors []error `json:"-"`
 }
 
 // ReplicationSlotsConfiguration encapsulates the configuration
diff --git a/api/v1/zz_api_repo_funcs_to_copy.go b/api/v1/zz_api_repo_funcs_to_copy.go
deleted file mode 100644
index bd55f68d..00000000
--- a/api/v1/zz_api_repo_funcs_to_copy.go
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-Copyright © contributors to CloudNativePG, established as
-CloudNativePG a Series of LF Projects, LLC.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-
-SPDX-License-Identifier: Apache-2.0
-*/
-
-package v1
-
-// IMPORTANT:
-// This file contains the functions that need to be copied from the api/v1 package to the cloudnative-pg/api
-// repository. This is currently required because the controller-gen tool cannot generate DeepCopyInto for the
-// regexp type. This will be removed once the controller-gen tool supports this feature.
-
-// DeepCopyInto needs to be manually added for the controller-gen compiler to work correctly, given that it cannot
-// generate the DeepCopyInto for the regexp type.
-// The method is empty because we don't want to transfer the cache when invoking DeepCopyInto.
-func (receiver synchronizeReplicasCache) DeepCopyInto(*synchronizeReplicasCache) {}
diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go
index 6ec7f7fa..c8b3917c 100644
--- a/api/v1/zz_generated.deepcopy.go
+++ b/api/v1/zz_generated.deepcopy.go
@@ -3068,7 +3068,6 @@ func (in *SynchronizeReplicasConfiguration) DeepCopyInto(out *SynchronizeReplica
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
-	in.synchronizeReplicasCache.DeepCopyInto(&out.synchronizeReplicasCache)
 }
 
 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SynchronizeReplicasConfiguration.
diff --git a/internal/webhook/v1/cluster_webhook.go b/internal/webhook/v1/cluster_webhook.go
index 453de809..70914579 100644
--- a/internal/webhook/v1/cluster_webhook.go
+++ b/internal/webhook/v1/cluster_webhook.go
@@ -2059,11 +2059,11 @@ func (v *ClusterCustomValidator) validateReplicationSlots(r *apiv1.Cluster) fiel
 		return nil
 	}
 
-	if errs := r.Spec.ReplicationSlots.SynchronizeReplicas.ValidateRegex(); len(errs) > 0 {
+	if err := r.Spec.ReplicationSlots.SynchronizeReplicas.ValidateRegex(); err != nil {
 		return field.ErrorList{
 			field.Invalid(
 				field.NewPath("spec", "replicationSlots", "synchronizeReplicas", "excludePatterns"),
-				errs,
+				err,
 				"Cannot configure synchronizeReplicas. Invalid regexes were found"),
 		}
 	}



Test patch:
diff --git a/api/v1/cluster_funcs_test.go b/api/v1/cluster_funcs_test.go
index 95fbeba0..01799bd6 100644
--- a/api/v1/cluster_funcs_test.go
+++ b/api/v1/cluster_funcs_test.go
@@ -1189,7 +1189,7 @@ var _ = Describe("SynchronizeReplicasConfiguration", func() {
 	Context("CompileRegex", func() {
 		It("should return no errors when SynchronizeReplicasConfiguration is nil", func() {
 			synchronizeReplicas = nil
-			Expect(synchronizeReplicas.ValidateRegex()).To(BeEmpty())
+			Expect(synchronizeReplicas.ValidateRegex()).ToNot(HaveOccurred())
 		})
 
 		Context("when SynchronizeReplicasConfiguration is not nil", func() {
@@ -1198,7 +1198,7 @@ var _ = Describe("SynchronizeReplicasConfiguration", func() {
 			})
 
 			It("should compile patterns without errors", func() {
-				Expect(synchronizeReplicas.ValidateRegex()).To(BeEmpty())
+				Expect(synchronizeReplicas.ValidateRegex()).ToNot(HaveOccurred())
 			})
 
 			Context("when a pattern fails to compile", func() {
@@ -1207,16 +1207,11 @@ var _ = Describe("SynchronizeReplicasConfiguration", func() {
 				})
 
 				It("should return errors for the invalid pattern", func() {
-					errors := synchronizeReplicas.ValidateRegex()
-					Expect(errors).To(HaveLen(1))
+					err := synchronizeReplicas.ValidateRegex()
+					Expect(err).To(HaveOccurred())
 				})
 			})
 		})
-
-		It("should return no errors on subsequent calls when compile is called multiple times", func() {
-			Expect(synchronizeReplicas.ValidateRegex()).To(BeEmpty())
-			Expect(synchronizeReplicas.ValidateRegex()).To(BeEmpty())
-		})
 	})
 
 	Context("GetEnabled", func() {
@@ -1268,19 +1263,12 @@ var _ = Describe("SynchronizeReplicasConfiguration", func() {
 				Expect(isExcludedByUser).To(BeTrue())
 			})
 
-			It("should compile patterns before checking for exclusion when compile is not called", func() {
-				Expect(synchronizeReplicas.compiledPatterns).To(BeEmpty())
-				isExcludedByUser, err := synchronizeReplicas.IsExcludedByUser("pattern1MatchingSlot")
-				Expect(err).ToNot(HaveOccurred())
-				Expect(isExcludedByUser, err).To(BeTrue())
-				Expect(synchronizeReplicas.compiledPatterns).To(HaveLen(2))
-			})
-
 			It("should return an error in case of an invalid pattern", func() {
 				synchronizeReplicas.ExcludePatterns = []string{"([a-zA-Z]+"}
 				isExcludedByUser, err := synchronizeReplicas.IsExcludedByUser("test")
 				Expect(err).To(HaveOccurred())
-				Expect(err.Error()).To(Equal("error parsing regexp: missing closing ): `([a-zA-Z]+`"))
+				Expect(err.Error()).To(Equal("failed to compile regex patterns: error parsing regexp: " +
+					"missing closing ): `([a-zA-Z]+`; "))
 				Expect(isExcludedByUser).To(BeFalse())
 			})
 		})