{"record":{"id":"3a0d8f7791eac15a","repo":"kubernetes/kubernetes","slug":"can-t-recheck-deletiontimestamp-v","errorCode":null,"errorMessage":"can't recheck DeletionTimestamp: %v","messagePattern":"can't recheck DeletionTimestamp: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/controller/controller_ref_manager.go","lineNumber":395,"sourceCode":"\t\t\t// Invalid error will be returned in two cases: 1. the ReplicaSet\n\t\t\t// has no owner reference, 2. the uid of the ReplicaSet doesn't\n\t\t\t// match, which means the ReplicaSet is deleted and then recreated.\n\t\t\t// In both cases, the error can be ignored.\n\t\t\treturn nil\n\t\t}\n\t}\n\treturn err\n}\n\n// RecheckDeletionTimestamp returns a CanAdopt() function to recheck deletion.\n//\n// The CanAdopt() function calls getObject() to fetch the latest value,\n// and denies adoption attempts if that object has a non-nil DeletionTimestamp.\nfunc RecheckDeletionTimestamp(getObject func(context.Context) (metav1.Object, error)) func(context.Context) error {\n\treturn func(ctx context.Context) error {\n\t\tobj, err := getObject(ctx)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"can't recheck DeletionTimestamp: %v\", err)\n\t\t}\n\t\tif obj.GetDeletionTimestamp() != nil {\n\t\t\treturn fmt.Errorf(\"%v/%v has just been deleted at %v\", obj.GetNamespace(), obj.GetName(), obj.GetDeletionTimestamp())\n\t\t}\n\t\treturn nil\n\t}\n}\n\n// ControllerRevisionControllerRefManager is used to manage controllerRef of ControllerRevisions.\n// Three methods are defined on this object 1: Classify 2: AdoptControllerRevision and\n// 3: ReleaseControllerRevision which are used to classify the ControllerRevisions into appropriate\n// categories and accordingly adopt or release them. See comments on these functions\n// for more details.\ntype ControllerRevisionControllerRefManager struct {\n\tBaseControllerRefManager\n\tcontrollerKind schema.GroupVersionKind\n\tcrControl      ControllerRevisionControlInterface\n}","sourceCodeStart":377,"sourceCodeEnd":413,"githubUrl":"https://github.com/kubernetes/kubernetes/blob/94c136764292cc5fac976c0de6587daaea56410f/pkg/controller/controller_ref_manager.go#L377-L413","documentation":"Returned by the CanAdopt closure produced by RecheckDeletionTimestamp when its getObject callback errors. The closure re-GETs the parent controller object to check for a fresh DeletionTimestamp; if the GET fails (not-found, network, conflict), this error is returned and blocks all adoptions by that ControllerRefManager instance for the current sync pass.","triggerScenarios":"RecheckDeletionTimestamp returns a closure; the closure calls getObject(ctx); getObject errors. Common callers pass a lister Get or a live client Get. Failures: parent not found (deleted), apiserver unreachable, watch cache stale returning an error.","commonSituations":"Parent controller object (Deployment/ReplicaSet) deleted between sync start and the CanAdopt call; informer cache returning a stale/missing object; transient apiserver error; parent recreated with a new UID causing not-found on the old UID.","solutions":["Treat as transient: the next sync pass creates a new ControllerRefManager (and thus a new CanAdopt) which re-checks.","If getObject uses a lister and persistently fails, restart the controller to reset the informer cache.","Verify the parent object exists with the expected UID; if it was deleted, this is expected behavior.","If getObject uses a live client, confirm apiserver reachability."],"exampleFix":"// before\nreturn func(ctx context.Context) error {\n    obj, err := getObject(ctx)\n    if err != nil {\n        return fmt.Errorf(\"can't recheck DeletionTimestamp: %v\", err)\n    }\n    ...\n}\n// after: treat not-found as a benign 'already deleted' rather than an opaque error\nreturn func(ctx context.Context) error {\n    obj, err := getObject(ctx)\n    if err != nil {\n        if apierrors.IsNotFound(err) {\n            return fmt.Errorf(\"can't recheck DeletionTimestamp: object has been deleted\")\n        }\n        return fmt.Errorf(\"can't recheck DeletionTimestamp: %v\", err)\n    }\n    ...\n}","handlingStrategy":"retry","validationCode":"// Verify parent object is reachable before constructing the CanAdopt closure\nif _, err := getObject(ctx); err != nil {\n    return fmt.Errorf(\"parent not reachable for DeletionTimestamp recheck: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"// In the controller sync loop, treat CanAdopt failures as transient\nif _, _, err := m.ClaimReplicaSets(ctx, sets); err != nil {\n    if strings.Contains(err.Error(), \"can't recheck DeletionTimestamp\") {\n        return err // requeue; next pass rebuilds the manager\n    }\n}","preventionTips":["Construct a fresh ControllerRefManager each sync pass so CanAdopt always re-checks.","Use a live-client GET (not a stale lister) inside getObject for accurate DeletionTimestamp.","Treat not-found as 'parent deleted' rather than a hard error."],"tags":["kubernetes-controller","owner-references","adoption","garbage-collection","deletion"],"backgroundTag":null,"analyzedSha":"94c136764292cc5fac976c0de6587daaea56410f","analyzedAt":"2026-08-08T23:58:27.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}