{"record":{"id":"b9ebb834e04cd6a4","repo":"apache/druid","slug":"unable-to-run-cleaning-action","errorCode":null,"errorMessage":"Unable to run cleaning action","messagePattern":"Unable to run cleaning action","errorType":"exception","errorClass":"java.lang.RuntimeException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/java/util/common/Cleaners.java","lineNumber":136,"sourceCode":"    public Cleanable register(Object object, Runnable runnable)\n    {\n      try {\n        Object cleanable = (Object) register.invoke(object, runnable);\n        return createCleanable(clean, cleanable);\n      }\n      catch (Throwable t) {\n        throw new RuntimeException(\"Unable to register cleaning action\", t);\n      }\n    }\n\n    private static Cleanable createCleanable(MethodHandle clean, Object cleanable)\n    {\n      return () -> {\n        try {\n          clean.invoke(cleanable);\n        }\n        catch (Throwable t) {\n          throw new RuntimeException(\"Unable to run cleaning action\", t);\n        }\n      };\n    }\n  }\n}\n","sourceCodeStart":118,"sourceCodeEnd":142,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/java/util/common/Cleaners.java#L118-L142","documentation":"The Cleanable returned by Cleaners wraps a MethodHandle invocation of the JDK cleanable's clean(). If running that cleaning action throws, the lambda rethrows it as RuntimeException 'Unable to run cleaning action'. This means the underlying clean() call failed, typically because the cleanable was already cleaned or internal APIs misbehaved.","triggerScenarios":"Explicitly calling clean() (via the Cleanable) twice, or after the JVM already auto-cleaned the object; or the reflective clean invocation failing on an incompatible runtime.","commonSituations":"Double-cleaning resources, race between GC-triggered automatic cleaning and explicit clean, exotic JDKs where clean() behaves unexpectedly.","solutions":["Clean each resource exactly once; treat explicit clean as terminal and drop the reference afterwards.","Wrap clean() calls in try/catch of RuntimeException and ignore 'already cleaned'-style failures if idempotency is desired.","Verify JVM compatibility; on standard JDKs double-clean is the usual culprit."],"exampleFix":"// before\ncleanable.clean();\ncleanable.clean(); // second call throws\n// after\ncleanable.clean(); // once only; GC will handle the rest","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  cleanable.clean();\n} catch (RuntimeException e) {\n  // likely already cleaned; ignore or log\n}","preventionTips":["Call clean() at most once per resource","Clear references after explicit clean to avoid double-clean races","Log-and-continue if a clean races with GC-triggered cleaning"],"tags":["jvm","memory-cleanup","reflection","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}