From 97bb0c78caa91d6733b44df84da498e4e9a810c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Attila=20M=C3=A9sz=C3=A1ros?= Date: Wed, 29 Jul 2026 18:19:52 +0200 Subject: [PATCH] fix: do not NPE when adding a finalizer to a resource deleted mid-retry `conflictRetryingPatchPrimary` / `conflictRetryingPatch` re-read the resource from the API server after a 409 or 422 and then re-evaluate the precondition: resource = operation.inNamespace(ns).withName(name).get(); `get()` returns null if the resource was deleted in the meantime, so the next iteration calls the precondition with null. `removeFinalizer` anticipates this: r -> { if (r == null) { log.warn("Cannot remove finalizer since resource not exists."); return false; } return r.hasFinalizer(finalizerName); } but `addFinalizer` passes `r -> !r.hasFinalizer(finalizerName)`, which throws a NullPointerException instead of exiting cleanly. Gives `addFinalizer` the same null guard, in both `ResourceOperations` and the deprecated `PrimaryUpdateAndCacheUtils`. No test is added: reaching the retry path requires stubbing the client to answer 409/422 and then 404 through the whole fabric8 DSL chain, which the existing unit tests are not set up for. --- .../api/reconciler/PrimaryUpdateAndCacheUtils.java | 8 +++++++- .../operator/api/reconciler/ResourceOperations.java | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java index f74cd49ee7..594666eade 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/PrimaryUpdateAndCacheUtils.java @@ -289,7 +289,13 @@ public static

P addFinalizer( r.addFinalizer(finalizerName); return r; }, - r -> !r.hasFinalizer(finalizerName)); + r -> { + if (r == null) { + log.warn("Cannot add finalizer since resource not exists."); + return false; + } + return !r.hasFinalizer(finalizerName); + }); } /** diff --git a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperations.java b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperations.java index c4532aa284..a4a1075b32 100644 --- a/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperations.java +++ b/operator-framework-core/src/main/java/io/javaoperatorsdk/operator/api/reconciler/ResourceOperations.java @@ -1079,7 +1079,13 @@ public P addFinalizer(String finalizerName, boolean cacheOnly) { r.addFinalizer(finalizerName); return r; }, - r -> !r.hasFinalizer(finalizerName), + r -> { + if (r == null) { + log.warn("Cannot add finalizer since resource no longer exists."); + return false; + } + return !r.hasFinalizer(finalizerName); + }, cacheOnly); }