kubernetes/kubernetes · warning
can't recheck DeletionTimestamp: %v
Error message
can't recheck DeletionTimestamp: %v
What it means
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.
Source
Thrown at pkg/controller/controller_ref_manager.go:395
// Invalid error will be returned in two cases: 1. the ReplicaSet
// has no owner reference, 2. the uid of the ReplicaSet doesn't
// match, which means the ReplicaSet is deleted and then recreated.
// In both cases, the error can be ignored.
return nil
}
}
return err
}
// RecheckDeletionTimestamp returns a CanAdopt() function to recheck deletion.
//
// The CanAdopt() function calls getObject() to fetch the latest value,
// and denies adoption attempts if that object has a non-nil DeletionTimestamp.
func RecheckDeletionTimestamp(getObject func(context.Context) (metav1.Object, error)) func(context.Context) error {
return func(ctx context.Context) error {
obj, err := getObject(ctx)
if err != nil {
return fmt.Errorf("can't recheck DeletionTimestamp: %v", err)
}
if obj.GetDeletionTimestamp() != nil {
return fmt.Errorf("%v/%v has just been deleted at %v", obj.GetNamespace(), obj.GetName(), obj.GetDeletionTimestamp())
}
return nil
}
}
// ControllerRevisionControllerRefManager is used to manage controllerRef of ControllerRevisions.
// Three methods are defined on this object 1: Classify 2: AdoptControllerRevision and
// 3: ReleaseControllerRevision which are used to classify the ControllerRevisions into appropriate
// categories and accordingly adopt or release them. See comments on these functions
// for more details.
type ControllerRevisionControllerRefManager struct {
BaseControllerRefManager
controllerKind schema.GroupVersionKind
crControl ControllerRevisionControlInterface
}View on GitHub (pinned to 94c1367642)
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.
Example fix
// before
return func(ctx context.Context) error {
obj, err := getObject(ctx)
if err != nil {
return fmt.Errorf("can't recheck DeletionTimestamp: %v", err)
}
...
}
// after: treat not-found as a benign 'already deleted' rather than an opaque error
return func(ctx context.Context) error {
obj, err := getObject(ctx)
if err != nil {
if apierrors.IsNotFound(err) {
return fmt.Errorf("can't recheck DeletionTimestamp: object has been deleted")
}
return fmt.Errorf("can't recheck DeletionTimestamp: %v", err)
}
...
} Defensive patterns
Strategy: retry
Validate before calling
// Verify parent object is reachable before constructing the CanAdopt closure
if _, err := getObject(ctx); err != nil {
return fmt.Errorf("parent not reachable for DeletionTimestamp recheck: %v", err)
} Try / catch
// In the controller sync loop, treat CanAdopt failures as transient
if _, _, err := m.ClaimReplicaSets(ctx, sets); err != nil {
if strings.Contains(err.Error(), "can't recheck DeletionTimestamp") {
return err // requeue; next pass rebuilds the manager
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- can't adopt Pod %v/%v (%v): %v
- can't adopt ReplicaSet %v/%v (%v): %v
- %v/%v has just been deleted at %v
- attempt to adopt revision owned by %v
- invalid resource metric source: neither an average utilizati
AI-assisted analysis of kubernetes/kubernetes@94c1367642 (2026-08-08).
Data as JSON: /api/errors/3a0d8f7791eac15a.
Report an issue: GitHub.