diff --git a/pkg/customresourcestate/registry_factory.go b/pkg/customresourcestate/registry_factory.go index 2a2cb067fc..3087e16c6a 100644 --- a/pkg/customresourcestate/registry_factory.go +++ b/pkg/customresourcestate/registry_factory.go @@ -403,6 +403,12 @@ func (c *compiledStateSet) values(v interface{}) (result []eachValue, errs []err comparable := c.ValueFrom.Get(v) value, ok := comparable.(string) if !ok { + // If the path doesn't exist (nil), return empty results instead of an error. + // This is consistent with how Gauge handles nil values and is expected for + // status fields that don't exist at resource creation time. + if comparable == nil { + return []eachValue{}, nil + } return []eachValue{}, []error{fmt.Errorf("%s: expected value for path to be string, got %T", c.path, comparable)} } diff --git a/pkg/customresourcestate/registry_factory_test.go b/pkg/customresourcestate/registry_factory_test.go index 7f5d1a0928..a13c80eefe 100644 --- a/pkg/customresourcestate/registry_factory_test.go +++ b/pkg/customresourcestate/registry_factory_test.go @@ -333,6 +333,22 @@ func Test_values(t *testing.T) { newEachValue(t, 0, "phase", "bar"), newEachValue(t, 1, "phase", "foo"), }}, + {name: "stateset nil path", each: &compiledStateSet{ + compiledCommon: compiledCommon{ + path: mustCompilePath(t, "does", "not", "exist"), + }, + LabelName: "phase", + List: []string{"foo", "bar"}, + }, wantResult: []eachValue{}, wantErrors: nil}, + {name: "stateset non-string value", each: &compiledStateSet{ + compiledCommon: compiledCommon{ + path: mustCompilePath(t, "spec", "replicas"), + }, + LabelName: "phase", + List: []string{"1", "2"}, + }, wantResult: []eachValue{}, wantErrors: []error{ + errors.New("[spec,replicas]: expected value for path to be string, got float64"), + }}, {name: "status_conditions", each: &compiledGauge{ compiledCommon: compiledCommon{ path: mustCompilePath(t, "status", "conditions", "[type=Ready]", "status"),