Change:
What happened: Using client-go v1.18.8 to watch resources on API server versions 1.17.x and 1.18.0 - 1.18.5 After the connection to the server is temporarily interrupted the client never recovers from error See the earlier issue for steps to reproduce: This was assumed fixed by But it appears the fix for the client was (probably inadvertently) implemented in a non-backward-compatible fashion and only solves the issue when the server is running v1.18.6 or later as well.
/sig api-machinery
Cc
PR
We generally recommend having apiservers be updated first before all other components. But yeah - it's true that this doesn't work for clients being more fresh - let me take a look at your PR.
/cc
This will be addressed by (and the cherrypicking it back).
Issues go stale after 90d of inactivity. Mark the issue as fresh with . Stale issues rot after an additional 30d of inactivity and eventually close. If this issue is safe to close now please do so with . Send feedback to sig-testing, kubernetes/test-infra and/or . /lifecycle stale
This has been fixed by and corresponding cherrypicks.

Discussion:
"io" "math/rand" "reflect" <ins> "strings" </ins> "sync" "time"

return true } } <ins> // Matches the message returned by api server before 1.17.0 if strings.Contains(apierr.Status().Message, "Too large resource version") { return true } </ins> return false }

stopCh := make(chan struct{}) s := NewStore(MetaNamespaceKeyFunc) listCallRVs := []string{} <ins> version := 30 </ins> lw := &testLW{ WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {

}, ListFunc: func(options metav1.ListOptions) (runtime.Object, error) { listCallRVs = append(listCallRVs, options.ResourceVersion) <ins> resourceVersion := strconv.Itoa(version) </ins> switch options.ResourceVersion { // initial list

err := apierrors.NewTimeoutError("too large resource version", 1) err.ErrStatus.Details.Causes = []metav1.StatusCause{{Message: "Too large resource version"}} return nil, err <ins> // relist after the initial list (covers the error format used in api server before 1.17.0) case "40": err := apierrors.NewTimeoutError("Too large resource version", 1) return nil, err </ins> // relist from etcd after "too large" error case "": <del> return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: "30"}}, nil </del> <ins> version += 10 return &v1.PodList{ListMeta: metav1.ListMeta{ResourceVersion: resourceVersion}}, nil </ins> default: return nil, fmt.Errorf("unexpected List call: %s", options.ResourceVersion) }

// may be synced to a different version and they will never converge. // TODO: We should use etcd progress-notify feature to avoid this behavior but until this is // done we simply try to relist from now to avoid continuous errors on relists. <del> for i := 1; i <= 2; i++ { </del> <ins> for i := 1; i <= 3; i++ { </ins> // relist twice to cover the two variants of TooLargeResourceVersion api errors stopCh = make(chan struct{}) if err := r.ListAndWatch(stopCh); err != nil {

} } <del> expectedRVs := []string{"0", "20", "", "30", ""} </del> <ins> expectedRVs := []string{"0", "20", "", "30", "", "40", ""} </ins> if !reflect.DeepEqual(listCallRVs, expectedRVs) { t.Errorf("Expected series of list calls with resource version of %#v but got: %#v", expectedRVs, listCallRVs) }